$bucket统计年龄段必须显式指定严格升序的boundaries数组,字段需为整数类型,须设default兜底异常值,区间左闭右开,不可用$bucketAuto替代业务语义分组。

用 $bucket 统计年龄段分布时,必须显式定义 boundaries 数组
直接写 $bucket 却没给 boundaries,MongoDB 会报错 "boundaries" must be a non-empty array。这个字段不是可选的,哪怕你只想分两段(比如“未成年/成年”),也得手动列出所有断点,例如 [0, 18, 35, 60] 表示划分 [0,18), [18,35), [35,60), [60,∞) 四个桶。
常见错误是把年龄字段当字符串处理——如果 age 存的是字符串(如 "25"),$bucket 会按字典序比较,导致 "100" 被分进 [0,18) 桶。务必确认字段类型是整数,必要时用 $toInt 转换:
[
{ "$addFields": { "age_num": { "$toInt": "$age" } } },
{ "$bucket": {
"groupBy": "$age_num",
"boundaries": [0, 18, 35, 60],
"default": "unknown",
"output": { "count": { "$sum": 1 } }
}
}
]
default 字段不是可有可无的兜底项
漏写 default 会导致边界外的数据(比如 age 为 -5 或 null)被整个丢弃,不计入任何桶,统计总数对不上原始文档数。尤其当数据含缺失值或异常值时,default: "other" 是必加项。
注意 default 值不能和已有 boundary 区间重名,否则聚合会失败。它只接受字符串或 null,不能是数字或对象。
- 推荐统一设为
"other"或"invalid",便于后续排查 - 如果想把 null 和负数分开统计,得先用
$cond预处理,$bucket本身不支持多条件 fallback
boundaries 必须严格升序且无重复,否则聚合中断
写成 [18, 0, 35] 或 [18, 18, 35],MongoDB 会直接拒绝执行,报错 boundaries must be strictly increasing。开发时容易手误,尤其从 Excel 复制数值后带隐藏空格或换行。
实际使用中建议:
- 用数组字面量硬编码,避免从变量拼接(Node.js 中易出错)
- 若区间需动态计算(如按用户最大最小年龄自动分 5 桶),必须在应用层算好再传入 pipeline,MongoDB 不支持在
$bucket内部调用$min/$max - 测试时用
db.users.find({ age: { $lt: 0 } })主动查异常值,别等聚合跑完才发现 count 对不上
和 $bucketAuto 的关键区别:你控制分组逻辑,不是 MongoDB 自动切
$bucketAuto 会按文档数均分桶(比如强制 5 桶,每桶约 20% 用户),但无法保证“18-35 岁”这种业务语义区间。$bucket 才是你定规则、它来分——适合年龄、收入、订单金额这类有明确业务边界的场景。
性能上两者差异不大,但 $bucket 更稳定:只要 boundaries 数组长度合理(一般 ≤ 20),就不会因桶过多拖慢;而 $bucketAuto 在数据倾斜严重时(如 90% 用户年龄集中在 25±2 岁),可能生成大量空桶或极不均衡的区间。
真正容易被忽略的是:$bucket 的区间左闭右开,[a,b) 意味着 age=18 进第二桶,age=35 进第三桶。如果你的业务要求“35 岁及以上”,得把边界设成 [0, 18, 35, 60, 120],并确保 default 不覆盖 120+ 的真实高龄用户。


















