首页/数据/NoSQL 速查/聚合 $group 分组统计
MongoDB99 条

聚合 $group 分组统计

$group 按键分组并用累加器计算:_id 定义分组键,$sum/$avg/$min/$max/$push/$addToSet/$first/$last 产出指标。

NoSQL 速查数据更新于 2026-10-13

$group 是什么

$group 是聚合管道里的分组统计阶段:_id 定义分组键,其余字段用累加器($sum、$avg、$min、$max、$push、$addToSet、$first、$last)计算指标。分组键可以是一整个字段、字段组合对象,或 null 表示把全部文档视作一组。它对应 SQL 的 GROUP BY,但结果字段名由你自由命名。

基本信息

语法{ $group: { _id: <表达式>, 字段: { <累加器>: <表达式> } } }
单字段分组_id: "$sku"
组合键_id: { sku: "$sku", day: "$day" }
全集合一组_id: null
内存上限每组结果受 100MB 限制,超出需 allowDiskUse
位置通常紧跟在 $match 之后

典型使用场景

  • 按商品统计销量与订单数,做销量排行
  • 按用户统计下单次数与累计金额
  • 按天/月分桶统计趋势(配合 $dateToString)
  • 去重计数:用 $addToSet 收集后统计集合大小
  • 取每组首尾记录:先 $sort 再用 $first / $last
  • 多维度交叉统计:分组键用对象组合多个字段

分组统计示例

分组统计示例
db.orders.aggregate([
  { $match: { status: "paid" } },                                  # 先过滤缩小数据量
  { $group: { _id: "$sku", totalQty: { $sum: "$qty" }, avgQty: { $avg: "$qty" }, orders: { $sum: 1 }, users: { $addToSet: "$user" } } },
  { $project: { sku: "$_id", totalQty: 1, orders: 1, userCount: { $size: "$users" }, _id: 0 } },
  { $sort: { totalQty: -1 } }
])

常用累加器

累加器作用注意点
$sum求和或计数非数值会被忽略
$avg求平均依赖数值字段
$min / $max取极值可与 $sort 配合取首尾
$push收集为数组可能撑爆 16MB
$addToSet去重收集元素多时内存占用高
$first / $last取首尾值需先排序才有确定语义
$group 的输出只有 _id 和累加器字段,需要保留原始字段名时用 $project 重命名;分组键用对象时 _id 也会是对象。
$push 会把每组所有值都收进数组,分组基数大时可能超过单文档 16MB 上限并直接失败,改用 $addToSet 或先聚合降维。
先 $match 再 $group 与先 $group 再 $match 结果相同但代价差很多:前者只对候选数据分组,后者要对全量文档分组后再过滤。

分组统计实践要点

  • 分组键尽量选低基数字段,高基数分组会产出海量小桶
  • 先在 $match 里缩小范围再进入 $group,能明显降低内存压力
  • 需要保留原始字段时用 $first / $min 等累加器,不能直接输出裸列
  • 时间分桶用 $dateToString 或 $dateTrunc,注意时区口径
  • 结果要落库时在管道末尾用 $merge,可增量写入报表集合
  • 结果规模不确定时先用 $limit 试跑,避免一次跑爆内存

易错点

  • $group 默认每组可用 100MB 内存,大分组会报错,需要 allowDiskUse: true 或先缩小数据范围
  • 分组键写成字符串 "$sku" 才对,漏掉 $ 会变成按固定字面量分组的单一桶
  • 对缺失字段分组会全部落进 _id: null 这一组,统计前先用 $match 排除或显式兜底
  • 把 $push 用在无界数组上会让分组结果撑爆文档上限,应先限制每组元素数量

数据来源与参考

  • MongoDB Manual: $group
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌