首页 / MongoDB 入门教程 / $group 与累加器

MongoDB 入门教程

$group 与累加器

本教程共 50 篇 · 第 30 篇 · 更新于 2026-07-30 · 约 7 分钟阅读

MongoDBMongoDB 入门教程group累加器sum分组统计

30. $group 与累加器

本节目标:学会用 $group 按字段分组,并用 $sum/$avg/$max/$min/$first/$last/$push 等累加器在每组内做统计,得到「每个用户的订单数、总额、均值」这类报表。

分组统计是聚合最核心的能力。$group 把文档按某个「分组键」归拢成若干组,再对每组用累加器(Accumulator)汇总。我们先用订单数据看效果。

db.orders.insertMany([
  { _id: 1001, user_id: 1, status: "completed", total: 657 },
  { _id: 1002, user_id: 2, status: "completed", total: 1099 },
  { _id: 1003, user_id: 1, status: "shipped", total: 597 },
  { _id: 1004, user_id: 3, status: "pending", total: 528 },
  { _id: 1005, user_id: 2, status: "cancelled", total: 398 }
])

_id:分组键

$group 必须有一个 _id 字段,它的值决定「怎么分组」。写 "$_id字段" 就按那个字段分组;写 null 表示所有文档归为一组(全局统计)。

// 按 user_id 分组,统计每人的订单数
db.orders.aggregate([
  {
    $group: {
      _id: "$user_id",
      orderCount: { $sum: 1 }
    }
  }
])

结果会是 user_id=1 两组?不——用户 1 有两条(1001、1003),所以 _id:1orderCount 是 2;用户 2 是 2;用户 3 是 1。

Note

$sum: 1 表示「每组每来一条就加 1」,等价于计数。$sum: "$total" 则是把 total 字段累加起来。

累加器一览

累加器作用示例
$sum求和{ $sum: "$total" }
$avg平均值{ $avg: "$total" }
$max组内最大{ $max: "$total" }
$min组内最小{ $min: "$total" }
$first组内首条{ $first: "$status" }
$last组内末条{ $last: "$status" }
$push收集成数组{ $push: "$_id" }

一个 $group 用多个累加器

可以在同一个 $group 里同时算多个指标,效率比多次分组高:

// 每人的订单数、总金额、平均金额、最大单
db.orders.aggregate([
  {
    $group: {
      _id: "$user_id",
      orderCount: { $sum: 1 },
      totalAmount: { $sum: "$total" },
      avgAmount: { $avg: "$total" },
      maxAmount: { $max: "$total" }
    }
  }
])
Tip

$first/$last 的结果依赖文档进入 $group 的顺序。如果顺序重要,记得在 $group 之前先用 $sort 排好。

$push:把组内值收进数组

$push 把每组的某个字段收集成一个数组,适合「列出某人所有订单号」:

// 每人对应的订单 _id 列表
db.orders.aggregate([
  {
    $group: {
      _id: "$user_id",
      orderIds: { $push: "$_id" }
    }
  }
])

全局统计:_id 写 null

不想分组、只想算全集的总和与均值,把 _id 设成 null

// 所有订单的总额和均值
db.orders.aggregate([
  {
    $group: {
      _id: null,
      allTotal: { $sum: "$total" },
      allAvg: { $avg: "$total" }
    }
  }
])

组合 $match 再 $group

统计「已完成订单」的各用户总额,先过滤再分组:

db.orders.aggregate([
  { $match: { status: "completed" } },
  {
    $group: {
      _id: "$user_id",
      completedAmount: { $sum: "$total" }
    }
  }
])
Warning

$group 默认会把整个集合读进来分组,数据量大时很吃内存。MongoDB 对管道有 100MB 内存限制,超了会报错。要么前置 $match 缩小数据,要么加 allowDiskUse: true 允许落盘。

分组统计是报表的基石。下一章看聚合里的排序、分页和计数阶段。