Definición
$bucketClasifica los documentos entrantes en grupos, denominados buckets, según una expresión especificada y los límites de los buckets, y genera un documento por cada bucket. Cada documento de salida contiene un campo
_idcuyo valor especifica el límite inferior inclusivo del bucket. La opción de salida especifica los campos incluidos en cada documento de salida.$bucketsolo produce documentos de salida para los buckets que contienen al menos un documento de entrada.
Considerations
$bucket y restricciones de memoria
La etapa tiene un límite $bucket de 100 megabytes de RAM. De forma predeterminada, si la etapa supera este límite, devuelve un error. Para disponer de más espacio para el procesamiento de$bucket la etapa, utilice el
OpciónallowDiskUse para habilitar que las etapas de la canalización de agregación escriban datos en archivos temporales.
Sintaxis
{ $bucket: { groupBy: <expression>, boundaries: [ <lowerbound1>, <lowerbound2>, ... ], default: <literal>, output: { <output1>: { <$accumulator expression> }, ... <outputN>: { <$accumulator expression> } } } }
El documento $bucket contiene los siguientes campos:
Campo | Tipo | Descripción | |||
|---|---|---|---|---|---|
expresión | Una expresión para agrupar documentos. Para especificar una ruta de campo, anteponga el nombre del campo con un signo de dólar A menos que | ||||
arreglo | Un arreglo de valores basado en la expresión groupBy que especifica los límites para cada cubo. Cada par adyacente de valores actúa como el límite inferior inclusivo y el límite superior exclusivo para el contenedor. Debe especificar al menos dos límites. Los valores especificados deben estar en orden ascendente y todos del mismo tipo. La excepción es si los valores son de tipos numéricos mixtos, como:
Por ejemplo, un arreglo de
| ||||
literal | Opcional. Un literal que especifica el Si no se especifica, cada documento de entrada debe resolver la expresión El valor El valor de | ||||
Documento | Opcional. Un documento que especifica los campos que deben incluirse en los documentos de salida además del campo Si no especificas un documento Si especificas un documento |
Comportamiento
$bucket requiere que se cumpla al menos una de las siguientes condiciones o la operación arroja un error:
Cada documento de entrada resuelve la expresión groupBy a un valor dentro de uno de los rangos de intervalos especificados por límites, o
Se especifica un valor por defecto para los documentos bucket cuyos valores
groupByestán fuera deboundarieso son de un tipo BSON diferente a los valores deboundaries.
Si la expresión groupBy se resuelve en un arreglo o un documento, $bucket organiza los documentos de entrada en buckets utilizando la lógica de comparación de $sort.
Ejemplos
Agrupar por año y aplicar un filtro por resultados de buckets
En mongosh, cree una colección de muestra llamada artists con los siguientes 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" } ])
La siguiente operación agrupa los documentos en buckets según el campo year_born y los filtra basándose en el número de documentos en los 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} } } ] )
- Primera etapa
La etapa
$bucketagrupa los documentos en buckets según el campoyear_born. Los buckets tienen los siguientes límites:[1840, 1850) con límite inferior inclusivo
1840y límite superior exclusivo1850.[1850, 1860) con límite inferior inclusivo
1850y límite superior exclusivo1860.[1860, 1870) con límite inferior inclusivo
1860y límite superior exclusivo1870.[1870, 1880) con límite inferior inclusivo
1870y límite superior exclusivo1880.Si un documento no contenía el campo
year_borno su campoyear_bornestaba fuera de los rangos anteriores, se colocaría en el depósito por defecto con el valor_id"Other".
La etapa incluye el documento de salida para determinar los campos a devolver:
CampoDescripción_idLímite inferior inclusivo del bucket.
countCantidad de documentos en el bucket.
artistsArreglo de documentos que contienen información sobre cada artista en el bucket. Cada documento contiene la información del artista.
name, que es una concatenación (es decir,$concat) de lafirst_nameylast_namedel artista.year_born
Esta etapa pasa los siguientes documentos a la siguiente etapa:
{ "_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
La etapa
$matchfiltra la salida de la etapa anterior para devolver solo los buckets que contienen más de 3 documentos.La operación devuelve el siguiente 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 } ] }
Utiliza $bucket con $facet para clasificar por múltiples campos
Puedes usar la etapa $facet para realizar múltiples agregaciones $bucket en una sola etapa.
En mongosh, cree una colección de muestra llamada artwork con los siguientes documentos:
db.artwork.insertMany([ { "_id" : 1, "title" : "The Pillars of Society", "artist" : "Grosz", "year" : 1926, "price" : Decimal128("199.99") }, { "_id" : 2, "title" : "Melancholy III", "artist" : "Munch", "year" : 1902, "price" : Decimal128("280.00") }, { "_id" : 3, "title" : "Dancer", "artist" : "Miro", "year" : 1925, "price" : Decimal128("76.04") }, { "_id" : 4, "title" : "The Great Wave off Kanagawa", "artist" : "Hokusai", "price" : Decimal128("167.30") }, { "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931, "price" : Decimal128("483.00") }, { "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913, "price" : Decimal128("385.00") }, { "_id" : 7, "title" : "The Scream", "artist" : "Munch", "year" : 1893 /* No price*/ }, { "_id" : 8, "title" : "Blue Flower", "artist" : "O'Keefe", "year" : 1918, "price" : Decimal128("118.42") } ])
La siguiente operación utiliza dos $bucket etapas dentro de una etapa $facet para crear dos agrupaciones, una por price y otra 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" } } } } } ] } } ] )
- Primer faceta
La primera faceta agrupa los documentos de entrada por
price. Los intervalos tienen los siguientes límites:[0, 200) con límite inferior inclusivo
0y límite superior exclusivo200.[200, 400) con límite inferior inclusivo
200y límite superior exclusivo400."Other", el bucket
defaultque contiene documentos sin precios o precios fuera de los rangos anteriores.
La etapa
$bucketincluye el documento de salida para determinar los campos que se deben devolver:CampoDescripción_idLímite inferior inclusivo del bucket.
countCantidad de documentos en el bucket.
artworkArreglo de documentos que contienen información sobre cada obra de arte en el bucket.
averagePriceEmplea el operador
$avgpara mostrar el precio promedio de todas las obras de arte en el bucket.- Segunda faceta
La segunda faceta agrupa los documentos de entrada por
year. Los contenedores tienen los siguientes límites:[1890, 1910) con límite inferior inclusivo
1890y límite superior exclusivo1910.[1910, 1920) con límite inferior inclusivo
1910y límite superior exclusivo1920.[1920, 1940) con límite inferior inclusivo
1910y límite superior exclusivo1940."Desconocido", el contenedor de
defaultque contiene documentos sin años o años fuera de los rangos anteriores.
La etapa
$bucketincluye el documento de salida para determinar los campos que se deben devolver:CampoDescripcióncountCantidad de documentos en el bucket.
artworkArreglo de documentos que contienen información sobre cada obra de arte en el bucket.
- Salida
La operación devuelve el siguiente documento:
{ "price" : [ // Output of first facet { "_id" : 0, "count" : 4, "artwork" : [ { "title" : "The Pillars of Society", "price" : Decimal128("199.99") }, { "title" : "Dancer", "price" : Decimal128("76.04") }, { "title" : "The Great Wave off Kanagawa", "price" : Decimal128("167.30") }, { "title" : "Blue Flower", "price" : Decimal128("118.42") } ], "averagePrice" : Decimal128("140.4375") }, { "_id" : 200, "count" : 2, "artwork" : [ { "title" : "Melancholy III", "price" : Decimal128("280.00") }, { "title" : "Composition VII", "price" : Decimal128("385.00") } ], "averagePrice" : Decimal128("332.50") }, { // Includes documents without prices and prices greater than 400 "_id" : "Other", "count" : 2, "artwork" : [ { "title" : "The Persistence of Memory", "price" : Decimal128("483.00") }, { "title" : "The Scream" } ], "averagePrice" : Decimal128("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" } ] } ] }
Los ejemplos de C# en esta página utilizan la base de datos sample_mflix de los conjuntos de datos de muestra de Atlas. Para aprender a crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de muestra, consulta Primeros pasos en la documentación del controlador de MongoDB .NET/C#.
La siguiente clase Movie modela los documentos en la colección sample_mflix.movies:
public class Movie { public ObjectId Id { get; set; } public int Runtime { get; set; } public string Title { get; set; } public string Rated { get; set; } public List<string> Genres { get; set; } public string Plot { get; set; } public ImdbData Imdb { get; set; } public int Year { get; set; } public int Index { get; set; } public string[] Comments { get; set; } [] public DateTime LastUpdated { get; set; } }
Nota
ConventionPack para Pascal Case
Las clases de C# en esta página utilizan Pascal case para los nombres de sus propiedades, pero los nombres de los campos en la colección de MongoDB utilizan camel case. Para tener en cuenta esta diferencia, se puede usar el siguiente código para registrar un ConventionPack cuando la aplicación se inicie:
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);
Para usar el controlador MongoDB.NET/C# para agregar una $bucket etapa a una canalización de agregación, llame a Bucket()método en un PipelineDefinition objeto.
El siguiente ejemplo crea una etapa de pipeline que agrupa los documentos entrantes por el valor de su campo Runtime, incluyendo el límite inferior y excluyendo el límite superior:
var pipeline = new EmptyPipelineDefinition<Movie>() .Bucket( groupBy: m => m.Runtime, boundaries: new List<int>() { 0, 71, 91, 121, 151, 201, 999 });
Para personalizar la operación $bucket, pasa un objeto AggregateBucketOptions al método Bucket(). El siguiente ejemplo realiza la misma operación $bucket que el ejemplo anterior, pero agrupa todos los documentos con un valor Runtime mayor que 999 en el bucket por defecto, llamado "Other":
var bucketOptions = new AggregateBucketOptions<BsonValue>() { DefaultBucket = (BsonValue)"Other" }; var pipeline = new EmptyPipelineDefinition<Movie>() .Bucket( groupBy: m => m.Runtime, boundaries: new List<BsonValue>() { 0, 71, 91, 121, 151, 201, 999 }, options: bucketOptions);
Los ejemplos de Node.js en esta página utilizan la base de datos sample_mflix de los conjuntos de datos de muestra de Atlas. Para aprender a crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de muestra, consulte Primeros pasos en la documentación del controlador de MongoDB Node.js.
Para utilizar el controlador de MongoDB Node.js para agregar una etapa de $bucket a una canalización de agregación, utilice el Operador $bucket en un objeto de canalización.
El siguiente ejemplo crea una etapa de pipeline que agrupa los documentos entrantes por el valor de su campo runtime, incluyendo el límite inferior y excluyendo el límite superior. La etapa de agregación agrupa todos los documentos con un valor runtime mayor que 999 en el bucket por defecto, llamado "other". A continuación, el ejemplo ejecuta el pipeline de agregación:
const pipeline = [ { $bucket: { groupBy: "$runtime", boundaries: [0, 17, 91, 121, 151, 201, 999], default: "other" } } ]; const cursor = collection.aggregate(pipeline); return cursor;
Obtén más información
Para aprender más sobre las etapas relacionadas del pipeline, consulta la guía $bucketAuto.