一、什麼是MongoDB聚合管道?¶
想象你有一堆散落的數據,比如學生的考試成績、購物訂單信息,現在要分析這些數據:比如統計各科平均分、找出最高分學生、按類別分組統計等。MongoDB的聚合管道就像一條“數據流水線”,你可以把數據依次經過多個“加工站”(稱爲“階段”),每個加工站對數據做不同處理,最後得到你想要的分析結果。
舉個例子:
你有一個“學生成績表”集合(類似Excel表格),裏面記錄了每個學生的姓名、科目、分數。要分析“數學平均分”,你不需要先把所有數據導出到Excel,再手動計算,而是用聚合管道“一步到位”:先篩選出“科目=數學”的學生(篩選階段),再計算這些學生的平均分(分組統計階段)。
二、聚合管道的核心概念¶
聚合管道由多個“階段” 組成,每個階段是一個“加工站”,數據從第一個階段流到下一個,最終輸出結果。階段的順序很重要,因爲每個階段處理前一個階段的輸出。
核心階段和操作符¶
| 階段名(操作符) | 作用通俗解釋 | 類似SQL |
|---|---|---|
$match |
篩選數據(類似 find() 查詢) |
WHERE |
$project |
只保留需要的字段(或重命名/計算新字段) | SELECT |
$group |
按條件分組,統計數據(如平均分、總數) | GROUP BY |
$sort |
對結果排序 | ORDER BY |
$limit |
限制返回的數據量 | LIMIT |
三、實戰案例:從簡單到複雜¶
假設我們有一個名爲 students 的集合,數據結構如下(簡化版):
{
"_id": 1,
"name": "張三",
"class": 1,
"subject": "數學",
"score": 85
},
{
"_id": 2,
"name": "李四",
"class": 1,
"subject": "數學",
"score": 92
},
{
"_id": 3,
"name": "王五",
"class": 2,
"subject": "數學",
"score": 78
}
案例1:篩選+投影(只看數學成績)¶
需求:找出1班學生的數學成績,只顯示姓名和分數。
代碼實現:
db.students.aggregate([
// 階段1:篩選班級=1且科目=數學的學生
{ $match: { class: 1, subject: "數學" } },
// 階段2:只保留姓名和分數字段
{ $project: { _id: 0, name: 1, score: 1 } }
])
輸出結果:
{ "name": "張三", "score": 85 },
{ "name": "李四", "score": 92 }
解釋:
- $match 相當於 SQL 的 WHERE class=1 AND subject="數學",只保留符合條件的文檔。
- $project 中的 _id: 0 表示不顯示默認的 _id 字段,name: 1 和 score: 1 表示顯示這兩個字段。
案例2:分組統計(按科目計算平均分)¶
需求:按“科目”分組,計算每個科目的平均分數。
代碼實現:
db.students.aggregate([
// 階段1:按科目分組,計算平均分
{ $group: {
_id: "$subject", // 分組依據:科目字段
avgScore: { $avg: "$score" } // 計算平均分,$avg 是累加器操作符
}
},
// 階段2:按平均分降序排序
{ $sort: { avgScore: -1 } }
])
輸出結果:
{ "_id": "數學", "avgScore": 85.0 },
{ "_id": "語文", "avgScore": 76.5 } // 假設還有語文數據
解釋:
- $group 的 _id: "$subject" 表示按“科目”字段分組。
- avgScore 是自定義的統計結果名,$avg: "$score" 表示對每個分組的 score 字段求平均值。
- $sort 按 avgScore 降序排列(-1 表示降序,1 表示升序)。
案例3:多階段組合(統計班級平均分+總人數)¶
需求:統計每個班級每個科目的平均分和總人數。
代碼實現:
db.students.aggregate([
// 階段1:按班級+科目分組
{ $group: {
_id: { class: "$class", subject: "$subject" }, // 複合分組:班級+科目
totalStudents: { $sum: 1 }, // 總人數:每個文檔+1
avgScore: { $avg: "$score" } // 平均分
}
},
// 階段2:按班級排序
{ $sort: { "_id.class": 1, "_id.subject": 1 } }
])
輸出結果:
{ "_id": { "class": 1, "subject": "數學" }, "totalStudents": 2, "avgScore": 88.5 },
{ "_id": { "class": 2, "subject": "數學" }, "totalStudents": 1, "avgScore": 78.0 }
解釋:
- $group 的 _id 可以是一個對象,包含多個字段(班級+科目),實現複合分組。
- $sum: 1 是統計總人數的常用寫法(每個文檔貢獻1個計數)。
四、常用操作符速查表¶
| 操作符 | 作用 | 示例 |
|---|---|---|
$match |
篩選文檔 | { $match: { score: { $gt: 60 } } }(分數>60) |
$project |
控制輸出字段 | { $project: { name: 1, newScore: { $add: ["$score", 5] } } } |
$group |
分組並統計 | { $group: { _id: "$subject", total: { $sum: "$score" } } } |
$sort |
排序 | { $sort: { score: -1 } }(降序) |
$limit |
限制數量 | { $limit: 10 }(取前10條) |
$skip |
跳過數據 | { $skip: 5 }(跳過前5條) |
五、總結¶
MongoDB聚合管道就像“數據加工廠”,通過多個階段的組合,你可以輕鬆完成複雜的數據分析:
1. 篩選:用 $match 過濾不需要的數據;
2. 投影:用 $project 只保留關鍵信息;
3. 分組:用 $group 按條件統計(平均分、總數等);
4. 排序/限制:用 $sort 和 $limit 優化結果。
從簡單例子開始,逐步嘗試多階段組合,你會發現聚合管道比手動在代碼中處理數據更高效、更靈活!
小建議:多練習不同場景的組合(比如“先篩選再分組”“先排序再限制”),熟悉每個階段的作用,很快就能掌握~