Docs 菜单

Docs 主页开发应用程序MongoDB Manual

$bucketAuto(聚合)

在此页面上

  • 定义
  • 考虑因素
  • 行为
  • 例子
$bucketAuto

根据指定的表达式,将接收到的文档归类到特定数量的群组中(称为“存储桶”)。自动确定存储桶边界,以尝试将文档均匀地分配到指定数量的存储桶中。

每个存储桶在输出中都表示为文档。每个存储桶的文档包含:

  • 指定存储桶边界的 _id 对象。

    • _id.min 字段指定存储桶的包含下限。

    • _id.max 字段指定存储桶的上边界。此边界对于数列中的最后一个存储桶具有包含性,但对所有其他存储桶具有独占性。

  • 包含存储桶中的文档数量的 count 字段。如果未指定 output 文档,则默认包含 count 字段。

$bucketAuto阶段具有以下形式:

{
$bucketAuto: {
groupBy: <expression>,
buckets: <number>,
output: {
<output1>: { <$accumulator expression> },
...
}
granularity: <string>
}
}
字段
类型
说明
groupBy
表达式(expression)
对文件进行分组的表达式。如需指定字段路径,请在字段名称前加上美元符号 $,并用引号括起来。
buckets
整型
一个 32 位正整数,用于指定将输入文档按组分到的存储桶的数量。
output
文档

可选。文档,它指定了除 _id 字段之外要包含在输出文档中的字段。 要指定要包含的字段,必须使用累加器表达式:

<outputfield1>: { <accumulator>: <expression1> },
...

指定 output 时,输出文档不包含默认的 count 字段。明确指定 count 表达式为 output 文档的一部分,以便包含:

output: {
<outputfield1>: { <accumulator>: <expression1> },
...
count: { $sum: 1 }
}
granularity
字符串

可选。指定 首选数字系列 的字符串 用于确保计算出的边界边以首选舍入数或其10 次方结束。

仅当所有 groupBy 值都是数值且没有一个是 NaN 时可用。

支持的 granularity 值为:

  • "R5"

  • "R10"

  • "R20"

  • "R40"

  • "R80"

  • "1-2-5"

  • "E6"

  • "E12"

  • "E24"

  • "E48"

  • "E96"

  • "E192"

  • "POWERSOF2"

$bucketAuto阶段的 RAM 限制为100 MB。默认情况下,如果阶段超过此限制, $bucketAuto会返回错误。要为阶段处理留出更多空间,请使用allowDiskUse选项使聚合管道阶段能够将数据写入临时文件。

提示

另请参阅:

如果出现以下情况,则相应值可能小于指定的存储桶数量:

  • 输入文档的数量小于指定的存储桶数。

  • groupBy 表达式的唯一值的数量小于 buckets 的指定数量。

  • granularity 的间隔数量少于 buckets 的数量。

  • granularity 不够精细,无法将文档平均分布到指定数量的 buckets

如果 groupBy 表达式引用数组或文档,那么在确定存储桶边界之前,值的排列顺序与 $sort 中使用的顺序相同。

文档在存储桶中的均匀分布取决于 groupBy 字段的关联基数或唯一值的数量。如果关联基数不够高,$bucketAuto 阶段可能无法将结果平均分布于各个存储桶。

$bucketAuto接受可选的granularity 参数,该参数确保所有存储桶的边界遵循指定的 首选数字系列 。使用首选数字系列可以更好地控制在 表达式中的值范围中设置存储桶边界的位置。当groupBy groupBy表达式的范围呈指数扩展时,它们还可用于帮助以对数方式均匀地设置存储桶边界。

Renard 数列是一组数字,其计算方法是取 10 的 5、10、20、40 或 80 次方根,然后包括与该根的各次方相对应的值,这些值介于 1.0 到 10.0 之间(在 R80 的情况下为 10.3)。

granularity 设置为 R5R10R20R40R80 以将存储桶边界限制为数列的值。当 groupBy值(R80为10.3)超出 1.0 到 10.0 范围时,该数列的值将乘以 10 的幂。

例子

R5序列基于 10 的五次方根(1.58),并包括该根的各种幂(四舍五入),直到达到 10。R5序列的推导如下:

  • 10 0/5 = 1

  • 10 1/5 = 1.584 ~ 1.6

  • 10 2/5 = 2.511 ~ 2.5

  • 10 3/5 = 3.981 ~ 4.0

  • 10 4/5 = 6.309 ~ 6.3

  • 10 5/5 = 10

同样的方法也适用于其他 Renard 数列,可提供更细的粒度,即 1.0 和 10.0 之间的更多间隔(R80 为 10.3)。

E 数列与Renard数列的相似之处在于,它们都是从1开始细分区间。 0改为10 。 0乘以 10 的第6、第12、第24、第48、第96或192根,具有特定的相对误差。

granularity E6设置为E12E24E48E96 、 或E192 以将存储桶边界限制为数列的值。当10 groupBy值在 之外时,该数列的值将乘以1 的幂。0 更改为10 。0 范围。要了解有关 E 系列及其各自相对误差的更多信息,请参阅 首选数字系列

1-2-5 数列的行为类似于三值 Renard 数列(如果存在这样的数列数)。

granularity 设置为 1-2-5 可将存储桶边界限制为 10 的三次方根的各个幂(四舍五入到一位有效数字)。

例子

以下值属于 1-2-5 系列:0.1、0.2、0.5、1、2、5、10、20、50、100、200、500、1000 等等...

granularity 设置为 POWERSOF2,可将存储桶边界限制为 2 的幂次。

例子

以下数字遵循“2 的次方”序列:

  • 2 0 = 1

  • 2 1 = 2

  • 2 2 = 4

  • 2 3 = 8

  • 2 4 = 16

  • 2 5 = 32

  • 依此类推...

一个常见的实现方式是,诸如内存之类的各种计算机组件通常遵循首选数的 POWERSOF2 集合:

1、2、4、8、16、32、64、128、256、512、1024、2048 等等....

以下操作演示了指定不同的 granularity 值会如何影响 $bucketAuto 确定存储桶边界的方式。things 集合的 _id 的值从 0 到 99 不等:

{ _id: 0 }
{ _id: 1 }
...
{ _id: 99 }

granularity 的不同值替换为以下操作:

db.things.aggregate( [
{
$bucketAuto: {
groupBy: "$_id",
buckets: 5,
granularity: <granularity>
}
}
] )

下表中的结果表明不同的 granularity 值如何产生不同的存储桶边界:

粒度
结果
注意
无粒度
{ "_id" : { "min" : 0, "max" : 20 }, "count" : 20 }
{ "_id" : { "min" : 20, "max" : 40 }, "count" : 20 }
{ "_id" : { "min" : 40, "max" : 60 }, "count" : 20 }
{ "_id" : { "min" : 60, "max" : 80 }, "count" : 20 }
{ "_id" : { "min" : 80, "max" : 99 }, "count" : 20 }
R20
{ "_id" : { "min" : 0, "max" : 20 }, "count" : 20 }
{ "_id" : { "min" : 20, "max" : 40 }, "count" : 20 }
{ "_id" : { "min" : 40, "max" : 63 }, "count" : 23 }
{ "_id" : { "min" : 63, "max" : 90 }, "count" : 27 }
{ "_id" : { "min" : 90, "max" : 100 }, "count" : 10 }
E24
{ "_id" : { "min" : 0, "max" : 20 }, "count" : 20 }
{ "_id" : { "min" : 20, "max" : 43 }, "count" : 23 }
{ "_id" : { "min" : 43, "max" : 68 }, "count" : 25 }
{ "_id" : { "min" : 68, "max" : 91 }, "count" : 23 }
{ "_id" : { "min" : 91, "max" : 100 }, "count" : 9 }
1-2-5
{ "_id" : { "min" : 0, "max" : 20 }, "count" : 20 }
{ "_id" : { "min" : 20, "max" : 50 }, "count" : 30 }
{ "_id" : { "min" : 50, "max" : 100 }, "count" : 50 }
指定的存储桶数超过数列中的区间数。
POWERSOF2
{ "_id" : { "min" : 0, "max" : 32 }, "count" : 32 }
{ "_id" : { "min" : 32, "max" : 64 }, "count" : 32 }
{ "_id" : { "min" : 64, "max" : 128 }, "count" : 36 }
指定的存储桶数超过数列中的区间数。

请考虑包含以下文档的集合 artwork

{ "_id" : 1, "title" : "The Pillars of Society", "artist" : "Grosz", "year" : 1926,
"price" : NumberDecimal("199.99"),
"dimensions" : { "height" : 39, "width" : 21, "units" : "in" } }
{ "_id" : 2, "title" : "Melancholy III", "artist" : "Munch", "year" : 1902,
"price" : NumberDecimal("280.00"),
"dimensions" : { "height" : 49, "width" : 32, "units" : "in" } }
{ "_id" : 3, "title" : "Dancer", "artist" : "Miro", "year" : 1925,
"price" : NumberDecimal("76.04"),
"dimensions" : { "height" : 25, "width" : 20, "units" : "in" } }
{ "_id" : 4, "title" : "The Great Wave off Kanagawa", "artist" : "Hokusai",
"price" : NumberDecimal("167.30"),
"dimensions" : { "height" : 24, "width" : 36, "units" : "in" } }
{ "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931,
"price" : NumberDecimal("483.00"),
"dimensions" : { "height" : 20, "width" : 24, "units" : "in" } }
{ "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913,
"price" : NumberDecimal("385.00"),
"dimensions" : { "height" : 30, "width" : 46, "units" : "in" } }
{ "_id" : 7, "title" : "The Scream", "artist" : "Munch",
"price" : NumberDecimal("159.00"),
"dimensions" : { "height" : 24, "width" : 18, "units" : "in" } }
{ "_id" : 8, "title" : "Blue Flower", "artist" : "O'Keefe", "year" : 1918,
"price" : NumberDecimal("118.42"),
"dimensions" : { "height" : 24, "width" : 20, "units" : "in" } }

在以下操作中,根据 price 字段中的值将输入文档分为四个存储桶:

db.artwork.aggregate( [
{
$bucketAuto: {
groupBy: "$price",
buckets: 4
}
}
] )

该操作将返回以下文档:

{
"_id" : {
"min" : NumberDecimal("76.04"),
"max" : NumberDecimal("159.00")
},
"count" : 2
}
{
"_id" : {
"min" : NumberDecimal("159.00"),
"max" : NumberDecimal("199.99")
},
"count" : 2
}
{
"_id" : {
"min" : NumberDecimal("199.99"),
"max" : NumberDecimal("385.00")
},
"count" : 2
}
{
"_id" : {
"min" : NumberDecimal("385.00"),
"max" : NumberDecimal("483.00")
},
"count" : 2
}

$bucketAuto阶段可用于$facet阶段,以对来自artwork的同一组输入文档处理多个聚合管道。

以下聚合管道根据 priceyear 和计算出的 areaartwork 集合的文档分组到存储桶:

db.artwork.aggregate( [
{
$facet: {
"price": [
{
$bucketAuto: {
groupBy: "$price",
buckets: 4
}
}
],
"year": [
{
$bucketAuto: {
groupBy: "$year",
buckets: 3,
output: {
"count": { $sum: 1 },
"years": { $push: "$year" }
}
}
}
],
"area": [
{
$bucketAuto: {
groupBy: {
$multiply: [ "$dimensions.height", "$dimensions.width" ]
},
buckets: 4,
output: {
"count": { $sum: 1 },
"titles": { $push: "$title" }
}
}
}
]
}
}
] )

该操作将返回以下文档:

{
"area" : [
{
"_id" : { "min" : 432, "max" : 500 },
"count" : 3,
"titles" : [
"The Scream",
"The Persistence of Memory",
"Blue Flower"
]
},
{
"_id" : { "min" : 500, "max" : 864 },
"count" : 2,
"titles" : [
"Dancer",
"The Pillars of Society"
]
},
{
"_id" : { "min" : 864, "max" : 1568 },
"count" : 2,
"titles" : [
"The Great Wave off Kanagawa",
"Composition VII"
]
},
{
"_id" : { "min" : 1568, "max" : 1568 },
"count" : 1,
"titles" : [
"Melancholy III"
]
}
],
"price" : [
{
"_id" : { "min" : NumberDecimal("76.04"), "max" : NumberDecimal("159.00") },
"count" : 2
},
{
"_id" : { "min" : NumberDecimal("159.00"), "max" : NumberDecimal("199.99") },
"count" : 2
},
{
"_id" : { "min" : NumberDecimal("199.99"), "max" : NumberDecimal("385.00") },
"count" : 2 },
{
"_id" : { "min" : NumberDecimal("385.00"), "max" : NumberDecimal("483.00") },
"count" : 2
}
],
"year" : [
{ "_id" : { "min" : null, "max" : 1913 }, "count" : 3, "years" : [ 1902 ] },
{ "_id" : { "min" : 1913, "max" : 1926 }, "count" : 3, "years" : [ 1913, 1918, 1925 ] },
{ "_id" : { "min" : 1926, "max" : 1931 }, "count" : 2, "years" : [ 1926, 1931 ] }
]
}
← $bucket(聚合)