$bucket (agregação)
Definição
$bucket
Novidade na versão 3.4.
Categoriza documentos de entrada em grupos, chamados buckets, com base em uma expressão especificada e limites de bucket e gera um documento por cada bucket. Cada documento de saída contém um campo
_id
cujo valor especifica o limite inferior inclusivo do bloco. A opção saída especifica os campos incluídos em cada documento de saída.$bucket
produz somente documentos de saída para buckets que contenham pelo menos um documento de entrada.
Considerações
$bucket
e restrições de memória
O estágio $bucket
tem um limite de 100 megabytes de RAM. Por padrão, se o estágio exceder este limite, $bucket
retornará um erro. Para permitir mais espaço para o processamento do estágio, use a opção allowDiskUse para permitir que os estágios do pipeline de agregação gravem dados em arquivos temporários.
Sintaxe
{ $bucket: { groupBy: <expression>, boundaries: [ <lowerbound1>, <lowerbound2>, ... ], default: <literal>, output: { <output1>: { <$accumulator expression> }, ... <outputN>: { <$accumulator expression> } } } }
O documento $bucket
contém os seguintes campos:
Campo | Tipo | Descrição | |||
---|---|---|---|---|---|
expressão | Uma expressão pela qual agrupar documentos. Para especificar um caminho do campo, prefixe o nome do campo com um sinal de dólar A menos que | ||||
array | Uma array de valores com base na expressão groupBy que especifica os limites de cada bucket. Cada par adjacente de valores atua como o limite inferior inclusivo e o limite superior exclusivo para o bucket. Você deve especificar pelo menos dois limites. Os valores especificados devem estar em ordem crescente e todos do mesmo tipo. Exceto quando os valores são tipos numéricos mistos, como:
Por exemplo, uma array de
| ||||
literal | Opcional. Um literal que especifica o Se não for especificado, cada documento de entrada deverá resolver a expressão O valor O valor | ||||
documento | Opcional. Um documento que especifica os campos a serem incluídos nos documentos de saída, além do campo
Se você não especificar um documento de Se você especificar um documento de |
Comportamento
$bucket
requer que pelo menos uma das seguintes condições seja atendida ou que a operação apresente um erro:
Cada documento de entrada resolve a expressão groupBy para um valor dentro de um dos intervalos de bucket especificados por limites ou
Um valor padrão é especificado para armazenar os documentos cujos valores
groupBy
estão fora dosboundaries
ou de um tipo de BSON diferente dos valores emboundaries
.
Se a expressão groupBy
for resolvida para uma array ou um documento, $bucket
organizará os documentos de entrada em buckets utilizando a lógica de comparação de $sort
.
Exemplos
Bucket por ano e filtrar por resultados do bucket
No mongosh
, crie uma coleção de amostra denominada artists
com os seguintes documentos:
db.artists.insertMany([ { "_id" : 1, "last_name" : "Bernard", "first_name" : "Emil", "year_born" : 1868, "year_died" : 1941, "nationality" : "France" }, { "_id" : 2, "last_name" : "Rippl-Ronai", "first_name" : "Joszef", "year_born" : 1861, "year_died" : 1927, "nationality" : "Hungary" }, { "_id" : 3, "last_name" : "Ostroumova", "first_name" : "Anna", "year_born" : 1871, "year_died" : 1955, "nationality" : "Russia" }, { "_id" : 4, "last_name" : "Van Gogh", "first_name" : "Vincent", "year_born" : 1853, "year_died" : 1890, "nationality" : "Holland" }, { "_id" : 5, "last_name" : "Maurer", "first_name" : "Alfred", "year_born" : 1868, "year_died" : 1932, "nationality" : "USA" }, { "_id" : 6, "last_name" : "Munch", "first_name" : "Edvard", "year_born" : 1863, "year_died" : 1944, "nationality" : "Norway" }, { "_id" : 7, "last_name" : "Redon", "first_name" : "Odilon", "year_born" : 1840, "year_died" : 1916, "nationality" : "France" }, { "_id" : 8, "last_name" : "Diriks", "first_name" : "Edvard", "year_born" : 1855, "year_died" : 1930, "nationality" : "Norway" } ])
A operação a seguir agrupa os documentos em buckets de acordo com o campo year_born
e filtra com base na contagem de documentos nos buckets:
db.artists.aggregate( [ // First Stage { $bucket: { groupBy: "$year_born", // Field to group by boundaries: [ 1840, 1850, 1860, 1870, 1880 ], // Boundaries for the buckets default: "Other", // Bucket ID for documents which do not fall into a bucket output: { // Output for each bucket "count": { $sum: 1 }, "artists" : { $push: { "name": { $concat: [ "$first_name", " ", "$last_name"] }, "year_born": "$year_born" } } } } }, // Second Stage { $match: { count: {$gt: 3} } } ] )
- Primeira etapa
A etapa
$bucket
agrupa os documentos em buckets pelo campoyear_born
. Os blocos têm os seguintes limites:[1840, 1850) com limite inferior inclusivo de
1840
e limite superior exclusivo de1850
.[1850, 1860) com limite inferior inclusivo
1850
e limite superior exclusivo1860
.[1860, 1870) com limite inferior inclusivo
1860
e limite superior exclusivo1870
.[1870, 1880) com limite inferior inclusivo
1870
e limite superior exclusivo1880
.Se um documento não contivesse o campo
year_born
ou seu campoyear_born
estivesse fora dos intervalos acima, ele seria colocado no bucket padrão com o valor_id
"Other"
.
O estágio inclui o documento de saída para determinar os campos a serem retornados:
CampoDescrição_id
Limite inferior inclusivo do bucket.count
Contagem de documentos no bucket.artists
Array de documentos contendo informações sobre cada artista no bucket. Cada documento contém o seguinte sobre o artista:
name
, que é uma concatenação (ou seja,$concat
) dofirst_name
elast_name
do artista.year_born
Este estágio passa os seguintes documentos para o próximo estágio:
{ "_id" : 1840, "count" : 1, "artists" : [ { "name" : "Odilon Redon", "year_born" : 1840 } ] } { "_id" : 1850, "count" : 2, "artists" : [ { "name" : "Vincent Van Gogh", "year_born" : 1853 }, { "name" : "Edvard Diriks", "year_born" : 1855 } ] } { "_id" : 1860, "count" : 4, "artists" : [ { "name" : "Emil Bernard", "year_born" : 1868 }, { "name" : "Joszef Rippl-Ronai", "year_born" : 1861 }, { "name" : "Alfred Maurer", "year_born" : 1868 }, { "name" : "Edvard Munch", "year_born" : 1863 } ] } { "_id" : 1870, "count" : 1, "artists" : [ { "name" : "Anna Ostroumova", "year_born" : 1871 } ] } - Segunda etapa
O estágio
$match
filtra a saída do estágio anterior para retornar apenas buckets que contenham mais de três documentos.A operação retorna o seguinte documento:
{ "_id" : 1860, "count" : 4, "artists" : [ { "name" : "Emil Bernard", "year_born" : 1868 }, { "name" : "Joszef Rippl-Ronai", "year_born" : 1861 }, { "name" : "Alfred Maurer", "year_born" : 1868 }, { "name" : "Edvard Munch", "year_born" : 1863 } ] }
Use $bucket com $facet para executar Bucket por vários campos
Você pode usar o estágio $facet
para executar várias agregações $bucket
em um único estágio.
No mongosh
, crie uma coleção de amostra denominada artwork
com os seguintes documentos:
db.artwork.insertMany([ { "_id" : 1, "title" : "The Pillars of Society", "artist" : "Grosz", "year" : 1926, "price" : NumberDecimal("199.99") }, { "_id" : 2, "title" : "Melancholy III", "artist" : "Munch", "year" : 1902, "price" : NumberDecimal("280.00") }, { "_id" : 3, "title" : "Dancer", "artist" : "Miro", "year" : 1925, "price" : NumberDecimal("76.04") }, { "_id" : 4, "title" : "The Great Wave off Kanagawa", "artist" : "Hokusai", "price" : NumberDecimal("167.30") }, { "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931, "price" : NumberDecimal("483.00") }, { "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913, "price" : NumberDecimal("385.00") }, { "_id" : 7, "title" : "The Scream", "artist" : "Munch", "year" : 1893 /* No price*/ }, { "_id" : 8, "title" : "Blue Flower", "artist" : "O'Keefe", "year" : 1918, "price" : NumberDecimal("118.42") } ])
A operação a seguir usa dois estágios $bucket
dentro de um estágio $facet
para criar dois agrupamentos, um por price
e outro por year
:
db.artwork.aggregate( [ { $facet: { // Top-level $facet stage "price": [ // Output field 1 { $bucket: { groupBy: "$price", // Field to group by boundaries: [ 0, 200, 400 ], // Boundaries for the buckets default: "Other", // Bucket ID for documents which do not fall into a bucket output: { // Output for each bucket "count": { $sum: 1 }, "artwork" : { $push: { "title": "$title", "price": "$price" } }, "averagePrice": { $avg: "$price" } } } } ], "year": [ // Output field 2 { $bucket: { groupBy: "$year", // Field to group by boundaries: [ 1890, 1910, 1920, 1940 ], // Boundaries for the buckets default: "Unknown", // Bucket ID for documents which do not fall into a bucket output: { // Output for each bucket "count": { $sum: 1 }, "artwork": { $push: { "title": "$title", "year": "$year" } } } } } ] } } ] )
- Primeira faceta
A primeira faceta agrupa os documentos de entrada por
price
. Os buckets têm os seguintes limites:[0, 200) com limite inferior inclusivo
0
e limite superior exclusivo200
.[200, 400) com limite inferior inclusivo
200
e limite superior exclusivo400
."Other", o bucket
default
que contém documentos sem preços ou preços fora das faixas acima.
O estágio
$bucket
inclui o documento de saída para determinar os campos a serem retornados:CampoDescrição_id
Limite inferior inclusivo do bucket.count
Contagem de documentos no bucket.artwork
Array de documentos contendo informações sobre cada obra de arte no bucket.averagePrice
Emprega o operador$avg
para exibir o preço médio de todas as obras de arte no bucket.- Segunda faceta
A segunda faceta agrupa os documentos de entrada por
year
. Os buckets têm os seguintes limites:[1890, 1910) com limite inferior inclusivo de
1890
e limite superior exclusivo de1910
.[1910, 1920) com limite inferior inclusivo de
1910
e limite superior exclusivo de1920
.[1920, 1940) com limite inferior inclusivo de
1910
e limite superior exclusivo de1940
." Unknown ", o bucket
default
contendo documentos sem anos ou anos fora dos intervalos acima.
O estágio
$bucket
inclui o documento de saída para determinar os campos a serem retornados:CampoDescriçãocount
Contagem de documentos no bucket.artwork
Array de documentos contendo informações sobre cada obra de arte no bucket.- Saída
A operação retorna o seguinte documento:
{ "price" : [ // Output of first facet { "_id" : 0, "count" : 4, "artwork" : [ { "title" : "The Pillars of Society", "price" : NumberDecimal("199.99") }, { "title" : "Dancer", "price" : NumberDecimal("76.04") }, { "title" : "The Great Wave off Kanagawa", "price" : NumberDecimal("167.30") }, { "title" : "Blue Flower", "price" : NumberDecimal("118.42") } ], "averagePrice" : NumberDecimal("140.4375") }, { "_id" : 200, "count" : 2, "artwork" : [ { "title" : "Melancholy III", "price" : NumberDecimal("280.00") }, { "title" : "Composition VII", "price" : NumberDecimal("385.00") } ], "averagePrice" : NumberDecimal("332.50") }, { // Includes documents without prices and prices greater than 400 "_id" : "Other", "count" : 2, "artwork" : [ { "title" : "The Persistence of Memory", "price" : NumberDecimal("483.00") }, { "title" : "The Scream" } ], "averagePrice" : NumberDecimal("483.00") } ], "year" : [ // Output of second facet { "_id" : 1890, "count" : 2, "artwork" : [ { "title" : "Melancholy III", "year" : 1902 }, { "title" : "The Scream", "year" : 1893 } ] }, { "_id" : 1910, "count" : 2, "artwork" : [ { "title" : "Composition VII", "year" : 1913 }, { "title" : "Blue Flower", "year" : 1918 } ] }, { "_id" : 1920, "count" : 3, "artwork" : [ { "title" : "The Pillars of Society", "year" : 1926 }, { "title" : "Dancer", "year" : 1925 }, { "title" : "The Persistence of Memory", "year" : 1931 } ] }, { // Includes documents without a year "_id" : "Unknown", "count" : 1, "artwork" : [ { "title" : "The Great Wave off Kanagawa" } ] } ] }