快速上手MongoDB聚合:$match和$group操作符詳解

MongoDB的聚合管道就像一條數據處理的流水線,我們可以把數據依次通過不同的“工序”(聚合操作符)進行篩選、統計和轉換,最終得到想要的結果。今天我們來學習聚合管道中最常用的兩個操作符:$match$group,幫你快速上手MongoDB的聚合分析。

一、MongoDB聚合管道基礎

聚合管道由多個階段組成,每個階段對應一個操作符(如$match$group),數據從左到右依次經過每個階段處理。我們用一個示例集合來理解,假設我們有一個學生成績集合students,文檔結構如下:

{ "_id": 1, "name": "張三", "subject": "數學", "score": 90, "class": "一班" }
{ "_id": 2, "name": "李四", "subject": "語文", "score": 85, "class": "一班" }
{ "_id": 3, "name": "王五", "subject": "數學", "score": 78, "class": "二班" }
{ "_id": 4, "name": "趙六", "subject": "語文", "score": 92, "class": "二班" }
{ "_id": 5, "name": "錢七", "subject": "數學", "score": 88, "class": "一班" }

二、$match:篩選數據的“過濾器”

$match就像SQL中的WHERE子句,用來篩選出符合條件的文檔,只把滿足條件的文檔傳遞給下一個階段,避免後續處理無效數據。

語法

{ $match: { <查詢條件> } }

<查詢條件>find()方法的條件一致,支持等於、大於、小於、包含等操作符,例如:
- 等於:{ class: "一班" }(篩選班級爲“一班”的文檔)
- 大於:{ score: { $gt: 80 } }(篩選分數大於80的文檔)
- 包含:{ subject: { $in: ["數學", "語文"] } }(篩選科目爲數學或語文的文檔)

示例:篩選“一班”的學生成績

db.students.aggregate([
  { $match: { class: "一班" } } // 只保留class爲“一班”的文檔
])

執行後會返回所有class爲“一班”的3條文檔:

{ "_id": 1, "name": "張三", "subject": "數學", "score": 90, "class": "一班" }
{ "_id": 2, "name": "李四", "subject": "語文", "score": 85, "class": "一班" }
{ "_id": 5, "name": "錢七", "subject": "數學", "score": 88, "class": "一班" }

三、$group:分組統計的“計算器”

篩選出數據後,$group按指定字段分組,並對每個組內的數據進行統計(如計數、求和、求平均等)。

語法

{ $group: { _id: <分組鍵>, <自定義字段>: { <累加器操作符>: <字段名> }, ... } }
  • _id:分組鍵,用來指定分組的依據(如按classsubject分組)。若設爲null,則整個集合作爲一個組。
  • 自定義字段:如student_countavg_score,用來存儲統計結果。
  • 累加器操作符:對每個組內的字段進行計算,常用的有:
  • $sum:求和(如$sum: "$score"計算總分)
  • $avg:求平均值(如$avg: "$score"計算平均分)
  • $count:計數(等價於$sum: 1,統計文檔數量)
  • $max/$min:取最大值/最小值

示例1:按班級分組統計學生數量

db.students.aggregate([
  { $group: { _id: "$class", student_count: { $sum: 1 } } } 
  // 按class分組,每個組計數1(統計學生數量)
])

結果:

{ "_id": "一班", "student_count": 3 },
{ "_id": "二班", "student_count": 2 }

示例2:按科目分組計算總分數

db.students.aggregate([
  { $group: { _id: "$subject", total_score: { $sum: "$score" } } } 
  // 按subject分組,計算每個科目的總分
])

結果:

{ "_id": "數學", "total_score": 90 + 78 + 88 = 256 },
{ "_id": "語文", "total_score": 85 + 92 = 177 }

示例3:按班級分組計算平均分數

db.students.aggregate([
  { $group: { _id: "$class", avg_score: { $avg: "$score" } } } 
  // 按class分組,計算每個班級的平均分
])

結果:

{ "_id": "一班", "avg_score": (90 + 85 + 88)/3  87.67 },
{ "_id": "二班", "avg_score": (78 + 92)/2 = 85 }

四、$match$group組合使用

實際分析中,我們常先篩選再分組。例如:統計“數學”科目中每個班級的平均分數

步驟:

  1. 第一步:用$match篩選出subject爲“數學”的文檔;
  2. 第二步:用$groupclass分組,計算平均分數。
db.students.aggregate([
  { $match: { subject: "數學" } }, // 篩選數學科目的學生
  { $group: { _id: "$class", avg_math_score: { $avg: "$score" } } } // 按班級分組算平均分
])

結果:

{ "_id": "一班", "avg_math_score": (90 + 88)/2 = 89 },
{ "_id": "二班", "avg_math_score": 78 }

總結

  • $match:像“過濾器”,先篩選數據,減少後續處理量。
  • $group:像“計算器”,按分組鍵分組後,用累加器操作符統計每個組的數據。
  • 兩者組合是聚合分析的核心模式:先過濾再分組統計。

通過這兩個操作符,你已經能完成基礎的統計分析。後續可學習$project(投影,只保留需要字段)、$sort(排序)等操作符,進一步擴展數據分析能力!

小夜