首页/数据/NoSQL 速查/聚合 $bucket 按值分桶
MongoDB99 条

聚合 $bucket 按值分桶

$bucket 按边界把数值或日期分到相邻区间并聚合;$bucketAuto 自动等分桶,适合分布类统计。

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

是什么

$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:边界明确、结果稳定、可解释,业务口径变化时也只需改一处配置。

易错点

  • boundaries 升序与类型一致是硬要求,写成乱序、重复或混用数值与字符串会直接报错
  • 忘记 default:只要有一个文档的值超出边界,整个聚合就失败,而数据里往往正好有脏值
  • 把 $bucket 的分组字段写成字符串型字段:字符串按字典序比较,分出的「区间」与业务直觉完全不符,应在分桶前先转换类型
  • 用 $bucketAuto 的结果做固定报表:桶边界会随数据分布变化,同一张报表在不同日期口径不一致

数据来源与参考

  • MongoDB Manual: $bucket
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌