是什么
$bucket 按你给定的边界值把文档分到相邻区间,再对每个区间做聚合;$bucketAuto 则不等你给边界,按数量自动切成若干桶。它们用于分布类统计:订单金额落在哪些区间、请求耗时分布在哪个量级、用户年龄如何分层。相比手写一长串 $cond,用边界表达更直观也更不容易写错。
基本信息
| 语法 | { $bucket: { groupBy, boundaries: [...], default, output } } |
|---|---|
| 边界要求 | 至少两个值,类型一致且升序;区间左闭右开,最后一个边界要能覆盖最大值 |
| 越界处理 | 落在边界之外的文档进入 default 桶;未指定 default 时遇到越界值直接报错 |
| 聚合字段 | output 里用 $sum / $avg / $max 等累加器定义每个桶的输出 |
| 自动分桶 | $bucketAuto:{ groupBy, buckets: N, granularity } |
典型使用场景
- 金额分层统计:按 0、100、1000、10000 的区间统计订单数与总金额
- 耗时分布:把请求耗时分成若干档位,判断长尾比例
- 用户分层:按活跃天数或消费额分档做运营人群划分
- 容量分档:按数据体积区间统计集合数量,用于资源规划
- 自动分位:分布未知时先用 $bucketAuto 快速看清数据落在什么范围
分桶统计
分桶统计
db.orders.aggregate([
{ $match: { status: "paid" } }, # 先过滤,减少进入分桶的文档
{ $bucket: {
groupBy: "$qty",
boundaries: [0, 10, 50, 100], # 左闭右开:0-9、10-49、50-99
default: "large", # 100 及以上进入兜底桶
output: { orders: { $sum: 1 }, totalQty: { $sum: "$qty" }, avgQty: { $avg: "$qty" } }
} }
])
db.orders.aggregate([ # 不知道分布时的自动分桶
{ $bucketAuto: { groupBy: "$amount", buckets: 5 } }
])边界与结果读法
| 配置或输出 | 含义 | 注意点 |
|---|---|---|
| boundaries | 桶边界数组,需升序且类型一致 | 乱序或重复直接报错 |
| default | 越界值的兜底桶名称 | 不设置且存在越界值时聚合报错 |
| output 累加器 | 每个桶的计算结果字段 | 可用 $sum、$avg、$max 等 |
| $bucketAuto 的 buckets | 期望的桶数量 | 实际桶数可能因数据分布略有出入 |
| granularity | 自动分桶使用优先数序列 | 仅对数值类型有效 |
边界要按实际取值范围设计:所有值都落在边界内时 default 桶不会出现,报表上看起来像少了一档;边界设置过窄则会造成意外报错或大量数据挤进兜底桶。
$bucketAuto 适合一次性探路,适合把结果直接用在固定报表的场景是 $bucket:边界明确、结果稳定、可解释,业务口径变化时也只需改一处配置。