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

$unwind (agregación)

$unwind

Descompone un campo de arreglo de los documentos de entrada para producir un documento para cada elemento. Cada documento de salida es el documento de entrada con el valor del campo del arreglo reemplazado por el elemento.

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.

Puede pasar un operando de ruta de campo o un operando de documento para descomponer un campo de arreglo.

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.

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 $ y encerrarlo entre comillas.

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

Opcional.

  • Si true, si el path es nulo, está ausente o es un arreglo vacío, $unwind genera el documento.

  • Si false, si path es nulo, está ausente o es un arreglo vacío, $unwind no genera un documento.

El valor por defecto es false.

  • Cuando el operando no se resuelve en un arreglo, pero no está ausente, null, o no es un arreglo vacío, $unwind trata el operando como un arreglo de un solo elemento.

  • Cuando el operando es null, falta o un arreglo vacío $unwind sigue el comportamiento establecido para la opción preserveNullAndEmptyArrays.

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.

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.

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" }

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 }

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 }

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 $unwind genera un nuevo documento para cada elemento en el arreglo sizes. La etapa utiliza la opción preserveNullAndEmptyArrays para incluir en la salida aquellos documentos donde el campo sizes esté 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 $group etapa agrupa los documentos por sizes y 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 $sort ordena los documentos por averagePrice en 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") }

Tip

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 $unwind genera un nuevo documento para cada elemento en el arreglo items:

{ "_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 $unwind produce un nuevo documento para cada elemento en los arreglos items.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 $group etapa 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") }

Volver

$unset

En esta página