Definición
Compatibilidad
Puedes usar $unwind para implementaciones alojadas en los siguientes entornos:
MongoDB Atlas: El servicio totalmente gestionado para implementaciones de MongoDB en la nube
MongoDB Enterprise: La versión basada en suscripción y autogestionada de MongoDB
MongoDB Community: La versión de MongoDB con código fuente disponible, de uso gratuito y autogestionada.
Sintaxis
Puede pasar un operando de ruta de campo o un operando de documento para descomponer un campo de arreglo.
Operando de ruta de campo
Puedes pasar la ruta de campo del arreglo a $unwind. Al utilizar esta sintaxis, $unwind no genera un documento si el valor del campo es nulo, está ausente o es un arreglo vacío.
{ $unwind: <field path> }
Cuando especifiques la ruta de campo, antepón el nombre del campo con un signo de dólar $ y enciérralo entre comillas.
Operando del documento con opciones
Nuevo en la versión 3.2.
Puedes pasar un documento a $unwind para especificar varias opciones de comportamiento.
{ $unwind: { path: <field path>, includeArrayIndex: <string>, preserveNullAndEmptyArrays: <boolean> } }
Campo | Tipo | Descripción |
|---|---|---|
string | Ruta de campo a un campo de arreglo. Para especificar una ruta de campo, anteponer el nombre del campo con un signo de dólar | |
string | Opcional. El nombre de un nuevo campo para contener el índice del arreglo del elemento. El nombre no puede comenzar con un signo de dólar | |
booleano |
Comportamientos
Ruta de campo sin arreglo
Cuando el operando no se resuelve en un arreglo, pero no está ausente,
null, o no es un arreglo vacío,$unwindtrata el operando como un arreglo de un solo elemento.Cuando el operando es
null, falta o un arreglo vacío$unwindsigue el comportamiento establecido para la opción preserveNullAndEmptyArrays.
Campo ausente
Si especificas una ruta para un campo que no existe en un documento de entrada o el campo es un arreglo vacío, $unwind, por defecto, ignora el documento de entrada y no se generarán documentos para ese documento de entrada.
Nuevo en la 3.2 versión: Para generar documentos en los que falta el campo de matriz, es nulo o una matriz vacía, utilice la opción preserveNullAndEmptyArrays.
Ejemplos
Desenrollar un arreglo
En mongosh, crea una colección de muestra llamada inventory con el siguiente documento:
db.inventory.insertOne({ "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] })
La siguiente agregación utiliza la etapa $unwind para generar un documento por cada elemento del arreglo sizes:
db.inventory.aggregate( [ { $unwind : "$sizes" } ] )
La operación devuelve los siguientes resultados:
{ "_id" : 1, "item" : "ABC1", "sizes" : "S" } { "_id" : 1, "item" : "ABC1", "sizes" : "M" } { "_id" : 1, "item" : "ABC1", "sizes" : "L" }
Cada documento es idéntico al documento de entrada, excepto por el valor del campo sizes, que ahora contiene un valor del arreglo sizes original.
includeArrayIndex y preserveNullAndEmptyArrays
Nuevo en la versión 3.2.
En mongosh, cree una colección de muestra llamada inventory2 con los siguientes documentos:
db.inventory2.insertMany([ { "_id" : 1, "item" : "ABC", price: NumberDecimal("80"), "sizes": [ "S", "M", "L"] }, { "_id" : 2, "item" : "EFG", price: NumberDecimal("120"), "sizes" : [ ] }, { "_id" : 3, "item" : "IJK", price: NumberDecimal("160"), "sizes": "M" }, { "_id" : 4, "item" : "LMN" , price: NumberDecimal("10") }, { "_id" : 5, "item" : "XYZ", price: NumberDecimal("5.75"), "sizes" : null } ])
Las siguientes operaciones son equivalentes y devuelven un documento por cada elemento $unwind del sizes campo. Si el sizes campo no se resuelve en una matriz, pero no es un array vacío, nulo o inexistente, $unwind trata el operando no array como una matriz de un solo elemento.
db.inventory2.aggregate( [ { $unwind: "$sizes" } ] ) db.inventory2.aggregate( [ { $unwind: { path: "$sizes" } } ] )
La operación devuelve los siguientes documentos:
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" } { "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" }
includeArrayIndex
La siguiente operación $unwind utiliza la opción includeArrayIndex para incluir el índice del arreglo en el resultado.
db.inventory2.aggregate( [ { $unwind: { path: "$sizes", includeArrayIndex: "arrayIndex" } }])
La operación desenrolla la matriz sizes e incluye el índice de la matriz en el nuevo campo arrayIndex. Si el campo sizes no se resuelve en una matriz, pero no es nulo, está vacío o no está incompleto, el campo arrayIndex es null.
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S", "arrayIndex" : NumberLong(0) } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M", "arrayIndex" : NumberLong(1) } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L", "arrayIndex" : NumberLong(2) } { "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M", "arrayIndex" : null }
preserveNullAndEmptyArrays
La siguiente operación $unwind utiliza la opción preserveNullAndEmptyArrays para incluir documentos cuyo campo sizes es nulo, está ausente o es un arreglo vacío.
db.inventory2.aggregate( [ { $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } } ] )
La salida incluye aquellos documentos donde el campo sizes es nulo, está ausente o es un arreglo vacío:
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" } { "_id" : 2, "item" : "EFG", "price" : NumberDecimal("120") } { "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" } { "_id" : 4, "item" : "LMN", "price" : NumberDecimal("10") } { "_id" : 5, "item" : "XYZ", "price" : NumberDecimal("5.75"), "sizes" : null }
Agrupar por valores desglosados
En mongosh, cree una colección de muestra llamada inventory2 con los siguientes documentos:
db.inventory2.insertMany([ { "_id" : 1, "item" : "ABC", price: NumberDecimal("80"), "sizes": [ "S", "M", "L"] }, { "_id" : 2, "item" : "EFG", price: NumberDecimal("120"), "sizes" : [ ] }, { "_id" : 3, "item" : "IJK", price: NumberDecimal("160"), "sizes": "M" }, { "_id" : 4, "item" : "LMN" , price: NumberDecimal("10") }, { "_id" : 5, "item" : "XYZ", price: NumberDecimal("5.75"), "sizes" : null } ])
El siguiente pipeline desenrolla el arreglo sizes y agrupa los documentos resultantes por los valores de tamaño desenrollado:
db.inventory2.aggregate( [ // First Stage { $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } }, // Second Stage { $group: { _id: "$sizes", averagePrice: { $avg: "$price" } } }, // Third Stage { $sort: { "averagePrice": -1 } } ] )
- Primera etapa:
La etapa
$unwindgenera un nuevo documento para cada elemento en el arreglosizes. La etapa utiliza la opción preserveNullAndEmptyArrays para incluir en la salida aquellos documentos donde el camposizesesté ausente, sea nulo o un arreglo vacío. Esta etapa pasa los siguientes documentos a la siguiente etapa:{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" } { "_id" : 2, "item" : "EFG", "price" : NumberDecimal("120") } { "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" } { "_id" : 4, "item" : "LMN", "price" : NumberDecimal("10") } { "_id" : 5, "item" : "XYZ", "price" : NumberDecimal("5.75"), "sizes" : null } - Segunda etapa:
La
$groupetapa agrupa los documentos porsizesy calcula el precio promedio de cada tamaño. Esta etapa pasa los siguientes documentos a la siguiente etapa:{ "_id" : "S", "averagePrice" : NumberDecimal("80") } { "_id" : "L", "averagePrice" : NumberDecimal("80") } { "_id" : "M", "averagePrice" : NumberDecimal("120") } { "_id" : null, "averagePrice" : NumberDecimal("45.25") } - Tercera etapa:
La etapa
$sortordena los documentos poraveragePriceen orden descendente. La operación devuelve el siguiente resultado:{ "_id" : "M", "averagePrice" : NumberDecimal("120") } { "_id" : "L", "averagePrice" : NumberDecimal("80") } { "_id" : "S", "averagePrice" : NumberDecimal("80") } { "_id" : null, "averagePrice" : NumberDecimal("45.25") }
Desenrollar arreglos incrustados
En mongosh, cree una colección de muestra llamada sales con los siguientes documentos:
db.sales.insertMany([ { _id: "1", "items" : [ { "name" : "pens", "tags" : [ "writing", "office", "school", "stationary" ], "price" : NumberDecimal("12.00"), "quantity" : NumberInt("5") }, { "name" : "envelopes", "tags" : [ "stationary", "office" ], "price" : NumberDecimal("19.95"), "quantity" : NumberInt("8") } ] }, { _id: "2", "items" : [ { "name" : "laptop", "tags" : [ "office", "electronics" ], "price" : NumberDecimal("800.00"), "quantity" : NumberInt("1") }, { "name" : "notepad", "tags" : [ "stationary", "school" ], "price" : NumberDecimal("14.95"), "quantity" : NumberInt("3") } ] } ])
La siguiente operación agrupa los artículos vendidos por sus etiquetas y calcula el monto total de ventas por cada etiqueta.
db.sales.aggregate([ // First Stage { $unwind: "$items" }, // Second Stage { $unwind: "$items.tags" }, // Third Stage { $group: { _id: "$items.tags", totalSalesAmount: { $sum: { $multiply: [ "$items.price", "$items.quantity" ] } } } } ])
- Primera etapa
La primera etapa
$unwindgenera un nuevo documento para cada elemento en el arregloitems:{ "_id" : "1", "items" : { "name" : "pens", "tags" : [ "writing", "office", "school", "stationary" ], "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "envelopes", "tags" : [ "stationary", "office" ], "price" : NumberDecimal("19.95"), "quantity" : 8 } } { "_id" : "2", "items" : { "name" : "laptop", "tags" : [ "office", "electronics" ], "price" : NumberDecimal("800.00"), "quantity" : 1 } } { "_id" : "2", "items" : { "name" : "notepad", "tags" : [ "stationary", "school" ], "price" : NumberDecimal("14.95"), "quantity" : 3 } } - Segunda etapa
La segunda etapa
$unwindproduce un nuevo documento para cada elemento en los arreglositems.tags:{ "_id" : "1", "items" : { "name" : "pens", "tags" : "writing", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "pens", "tags" : "office", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "pens", "tags" : "school", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "pens", "tags" : "stationary", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "envelopes", "tags" : "stationary", "price" : NumberDecimal("19.95"), "quantity" : 8 } } { "_id" : "1", "items" : { "name" : "envelopes", "tags" : "office", "price" : NumberDecimal("19.95"), "quantity" : 8 } } { "_id" : "2", "items" : { "name" : "laptop", "tags" : "office", "price" : NumberDecimal("800.00"), "quantity" : 1 } } { "_id" : "2", "items" : { "name" : "laptop", "tags" : "electronics", "price" : NumberDecimal("800.00"), "quantity" : 1 } } { "_id" : "2", "items" : { "name" : "notepad", "tags" : "stationary", "price" : NumberDecimal("14.95"), "quantity" : 3 } } { "_id" : "2", "items" : { "name" : "notepad", "tags" : "school", "price" : NumberDecimal("14.95"), "quantity" : 3 } } - Tercera etapa
La
$groupetapa agrupa los documentos por la etiqueta y calcula el importe total de ventas de artículos con cada etiqueta:{ "_id" : "writing", "totalSalesAmount" : NumberDecimal("60.00") } { "_id" : "stationary", "totalSalesAmount" : NumberDecimal("264.45") } { "_id" : "electronics", "totalSalesAmount" : NumberDecimal("800.00") } { "_id" : "school", "totalSalesAmount" : NumberDecimal("104.85") } { "_id" : "office", "totalSalesAmount" : NumberDecimal("1019.60") }