$bucket是MongoDB按数值范围分桶统计的聚合阶段,需指定升序boundaries数组生成左闭右开区间及other桶;而$group按字段值精确分组。$bucket必须设default防丢数据,且不支持分片下推,大数据量时需优化边界和前置过滤。

什么是 $bucket,它和 $group 有什么区别?
$bucket 是 MongoDB 的聚合阶段,专用于对数值字段做**等宽或自定义边界分桶**,再统计每桶数量(或其他聚合值)。它不是简单分组,而是先按数值范围“切片”,再对每片执行 $sum、$count 等操作。和纯 $group 不同:$group 需要明确字段值或表达式结果作为分组键,而 $bucket 只需提供边界数组,MongoDB 自动判断归属——适合处理连续数值分布,比如年龄、价格、响应时间。
必须提供 boundaries 数组,且必须升序排列
使用 $bucket 时,boundaries 是强制字段,类型为数值数组,例如 [0, 25, 35, 45, 60]。MongoDB 会据此生成 4 个桶:[0, 25)、[25, 35)、[35, 45)、[45, 60),以及一个 other 桶收容小于最小值或大于等于最大值的数据。
- 边界必须严格升序,否则报错
boundaries array must be sorted in ascending order - 边界不能含
null或字符串,只接受数字(包括NumberLong、Double) - 如果想包含上限(如闭区间
[45, 60]),得靠default配合$cond手动补,$bucket本身只支持左闭右开
用 output 定义每桶的统计逻辑,别漏掉 default
output 字段指定每个桶内要计算什么,比如计数、平均值、最大值。它是一个对象,键是输出字段名,值是聚合表达式;同时建议显式设置 default,否则超出边界的文档会被丢弃(不是归入 other,而是彻底不参与输出)。
{
$bucket: {
groupBy: "$price",
boundaries: [0, 100, 500, 1000],
default: "other",
output: {
count: { $sum: 1 },
avgRating: { $avg: "$rating" }
}
}
}
-
groupBy必须指向数值型字段,若字段可能为空或非数字,先用$cond过滤或转成$toDouble,否则该文档会进default桶 -
default值可以是字符串(如"other")或任意合法表达式,但不能省略——省略即静默丢弃 - 如果只想要计数,
output: { count: { $sum: 1 } }就够了;加多个字段不会显著拖慢,但注意内存占用
当数据量大或边界多时,注意性能与内存限制
$bucket 在内存中构建桶映射表,边界越多、文档越分散,内存消耗越高。在分片集群上,它无法下推到各个分片并行执行——所有匹配文档先被拉到主节点再分桶,容易触发 Exceeded memory limit for $group 错误。
- 超过 100 个边界时,建议改用
$switch+$group模拟,虽然写法啰嗦但可控性强 - 对超大数据集,先用
$match缩小范围(比如限定price: { $gt: 0 }),再$bucket,避免无效文档参与分桶 - 测试时加
{ allowDiskUse: true },但生产环境应优先优化边界粒度和前置过滤
边界设计不合理是最隐蔽的问题:太密导致大量空桶,太疏掩盖分布细节,最好结合 $min/$max 先探查数据范围再定 boundaries。











