$bucket报错“boundaries must be在升序”因边界数组未严格递增或含重复值;必须显式排序去重、确保全为数字类型;n个边界生成n+1桶,default需显式设置以防数据丢失;非数值字段须预转换,动态边界需预计算。

$bucket 是 MongoDB 中做区间分组统计最直接的工具,但它要求输入字段必须是数值类型,且必须显式定义边界数组——边界缺失或顺序错乱会直接报错 ExpressionDocumentError。
为什么 $bucket 总是报错 "boundaries must be in ascending order"
这是最常见的启动失败原因。$bucket 的 boundaries 参数不是随便列几个数就行,它必须严格递增,且不能有重复值。MongoDB 不会帮你排序或去重,传入 [10, 5, 15] 或 [5, 5, 10] 都会立刻失败。
- 检查边界数组是否用
sort()显式排过序,尤其当边界来自变量拼接时 - 确认所有边界值都是数字类型,
"5"(字符串)和5(数字)混用会导致隐式比较异常 - 边界长度决定分组数量:n 个边界值 → n+1 个桶(含
default桶)
如何正确设置 $bucket 的 default 分组
没有 default 字段时,落在边界外的数据会被直接丢弃——这不是 bug,是设计行为。比如边界为 [0, 10, 20],那么值为 -5 或 25 的文档不会进入任何桶。
- 务必显式添加
default: "other"(或其他有意义的字符串)来捕获异常值 -
default值可以是字符串、数字甚至null,但类型需与其它桶的group值一致,否则后续$group聚合可能出错 - 如果业务上不允许存在“异常值”,那就别设
default,但得提前清洗数据或加$match过滤
$bucket 和 $switch + $range 的性能差异在哪
用 $switch 模拟区间逻辑看似灵活,但实际执行更慢,且无法利用索引优化。$bucket 是原生聚合阶段,在 C++ 层直接处理,对大集合优势明显。
- 数据量超 10 万时,$bucket 比等效
$switch快 3–5 倍(实测 4.4+ 版本) - $bucket 支持在
$facet内并行使用,$switch无法做到 - 注意:$bucket 不能引用其他字段动态生成边界,边界必须是常量数组;需要动态边界得先用
$let+$function(v4.4+)预计算,再传入
常见误用:把非数值字段塞进 $bucket
例如对 status: "active" 或 created_at: ISODate("...") 直接套 $bucket,会触发 TypeError: cannot convert to number。
- 时间字段必须先转为数值:用
$toDate→$millisSinceEpoch,或$dateToString提取年/月再转$toInt - 枚举字符串需映射为序号:
$switch先转成数字,再喂给 $bucket - 空值(
null、missing)默认归入default桶,不报错但可能掩盖数据质量问题
真正麻烦的不是写法,而是边界定义和数据类型的隐式转换——一次没校验的 parseInt() 或意外的字符串字段,就能让整个聚合流水线静默丢数据。











