MongoDB聚合管道:初学者也能看懂的数据分析方法

一、什么是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: 1score: 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 字段求平均值。
- $sortavgScore 降序排列(-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 优化结果。

从简单例子开始,逐步尝试多阶段组合,你会发现聚合管道比手动在代码中处理数据更高效、更灵活!

小建议:多练习不同场景的组合(比如“先筛选再分组”“先排序再限制”),熟悉每个阶段的作用,很快就能掌握~

小夜