Docs Menu
Docs Home
/ /
Etapas de la pipeline de agregación

$bucket (etapa de agregación)

$bucket

Clasifica 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 _id cuyo valor especifica el límite inferior inclusivo del bucket. La opción de salida especifica los campos incluidos en cada documento de salida.

$bucket solo produce documentos de salida para los buckets que contienen al menos un documento de entrada.

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.

Tip

{
$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 $ y enciérrelo entre comillas.

A menos que $bucket incluya una especificación por defecto, cada documento de entrada debe resolver la ruta de campo groupBy o expresión a un valor que esté dentro de uno de los rangos especificados por los límites.

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:

[ 10, Long(20), Int32(30) ]

Por ejemplo, un arreglo de [ 0, 5, 10 ] crea dos buckets:

  • [0, 5) con límite inferior inclusivo 0 y límite superior exclusivo 5.

  • [5, 10) con límite inferior inclusivo 5 y límite superior exclusivo 10.

literal

Opcional. Un literal que especifica el _id de un bucket adicional que contiene todos los documentos cuyo resultado de la expresión groupBy no entra en un bucket especificado por límites.

Si no se especifica, cada documento de entrada debe resolver la expresión groupBy a un valor dentro de uno de los rangos de bucket especificados por boundaries o la operación arroja un error.

El valor default debe ser menor que el valor más bajo de boundaries, o mayor o igual al valor más alto de boundaries.

El valor de default puede ser de un tipo diferente al de las entradas en boundaries.

Documento

Opcional. Un documento que especifica los campos que deben incluirse en los documentos de salida además del campo _id. Para especificar el campo que deseas incluir, debes utilizar expresiones de acumulador.

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

Si no especificas un documento output, la operación devuelve un campo count que contiene el número de documentos en cada bucket.

Si especificas un documento output, solo se devuelven los campos especificados en el documento; es decir, el campo count no se devuelve a menos que esté explícitamente incluido en el documento output.

$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 groupBy están fuera de boundaries o son de un tipo BSON diferente a los valores de boundaries.

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.

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 $bucket agrupa los documentos en buckets según el campo year_born. Los buckets tienen los siguientes límites:

  • [1840, 1850) con límite inferior inclusivo 1840 y límite superior exclusivo 1850.

  • [1850, 1860) con límite inferior inclusivo 1850 y límite superior exclusivo 1860.

  • [1860, 1870) con límite inferior inclusivo 1860 y límite superior exclusivo 1870.

  • [1870, 1880) con límite inferior inclusivo 1870 y límite superior exclusivo 1880.

  • Si un documento no contenía el campo year_born o su campo year_born estaba 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:

Campo
Descripción

_id

Límite inferior inclusivo del bucket.

count

Cantidad de documentos en el bucket.

artists

Arreglo 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 la first_name y last_name del 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 $match filtra 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 }
]
}

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 0 y límite superior exclusivo 200.

  • [200, 400) con límite inferior inclusivo 200 y límite superior exclusivo 400.

  • "Other", el bucket default que contiene documentos sin precios o precios fuera de los rangos anteriores.

La etapa $bucket incluye el documento de salida para determinar los campos que se deben devolver:

Campo
Descripción

_id

Límite inferior inclusivo del bucket.

count

Cantidad de documentos en el bucket.

artwork

Arreglo de documentos que contienen información sobre cada obra de arte en el bucket.

averagePrice

Emplea el operador $avg para 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 1890 y límite superior exclusivo 1910.

  • [1910, 1920) con límite inferior inclusivo 1910 y límite superior exclusivo 1920.

  • [1920, 1940) con límite inferior inclusivo 1910 y límite superior exclusivo 1940.

  • "Desconocido", el contenedor de default que contiene documentos sin años o años fuera de los rangos anteriores.

La etapa $bucket incluye el documento de salida para determinar los campos que se deben devolver:

Campo
Descripción

count

Cantidad de documentos en el bucket.

artwork

Arreglo 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; }
[BsonElement("lastupdated")]
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;

Para aprender más sobre las etapas relacionadas del pipeline, consulta la guía $bucketAuto.

Volver

$addFields

En esta página