Definición
Compatibilidad
Puedes usar $unwind para implementaciones alojadas en los siguientes entornos:
- MongoDB Atlas: El servicio totalmente administrado 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
Pase 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. Con 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
Puedes pasar un documento a $unwind para especificar opciones.
{ $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 | Opcional.
El valor por defecto es |
Comportamientos
Ruta de campo sin arreglo
Cuando el valor en path no se resuelve en un arreglo, $unwind se comporta de la siguiente manera:
Si el valor no falta, no es
nully no es un arreglo vacío,$unwindgenera un solo documento utilizando el valor tal cual.Si
includeArrayIndexse especifica, el índice es0para entradas de arreglos ynullpara entradas que no sean de arreglos. Los documentos posteriores en la lista tienen un índice superior a0.
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.
Para generar documentos donde el campo de matriz no esté presente, sea nulo o sea una matriz vacía, utilice la opción preserveNullAndEmptyArrays.
Ejemplos
Los ejemplos de esta página utilizan datos del conjunto de datos sample_mflix. Para obtener más información sobre cómo cargar este conjunto de datos en la implementación autogestionada de MongoDB, consultar Cargar el conjunto de datos de muestra. Si realizó alguna modificación en las bases de datos de muestra, es posible que deba descartar y volver a crear las bases de datos para ejecutar los ejemplos de esta página.
Desenrollar un arreglo
La siguiente agregación utiliza la etapa $unwind para generar un documento por cada elemento del arreglo genres del documento de película Inception:
db.movies.aggregate( [ { $match: { title: "Inception" } }, { $project: { _id: 0, title: 1, genres: 1 } }, { $unwind: "$genres" } ] )
[ { genres: 'Action', title: 'Inception' }, { genres: 'Mystery', title: 'Inception' }, { genres: 'Sci-Fi', title: 'Inception' } ]
Cada documento de salida es idéntico al documento de entrada, excepto por el valor del campo genres, que ahora contiene un solo elemento del arreglo genres original.
Valores faltantes o no en forma de arreglo
La siguiente agregación utiliza la etapa $unwind con cuatro documentos de películas. Dos de los documentos ("La porta del cielo" y "Neecha Nagar") no tienen un campo genres:
db.movies.aggregate( [ { $match: { title: { $in: [ "Inception", "Brave", "La porta del cielo", "Neecha Nagar" ] } } }, { $project: { _id: 0, title: 1, genres: 1 } }, { $unwind: { path: "$genres" } } ] )
[ { genres: 'Animation', title: 'Brave' }, { genres: 'Adventure', title: 'Brave' }, { genres: 'Comedy', title: 'Brave' }, { genres: 'Action', title: 'Inception' }, { genres: 'Mystery', title: 'Inception' }, { genres: 'Sci-Fi', title: 'Inception' } ]
En los documentos
"Brave"y"Inception",genreses un arreglo poblado.$unwinddevuelve un documento para cada elemento.Los documentos
"La porta del cielo"y"Neecha Nagar"no tienen un campogenres, por lo tanto,$unwindno devuelve ningún documento para ellos.
Nota
La sintaxis { path: <FIELD> } es opcional. Las siguientes $unwind operaciones son equivalentes.
db.<COLLECTION>.aggregate( [ { $unwind: "<FIELD>" } ] )
db.<COLLECTION>.aggregate( [ { $unwind: { path: "<FIELD>" } } ] )
preserveNullAndEmptyArrays y includeArrayIndex
Los ejemplos preserveNullAndEmptyArrays e includeArrayIndex utilizan documentos de la colección sample_mflix.movies.
preserveNullAndEmptyArrays
La siguiente operación $unwind utiliza la opción preserveNullAndEmptyArrays para incluir documentos cuyo campo genres no está presente.
db.movies.aggregate( [ { $match: { title: { $in: [ "Inception", "Brave", "La porta del cielo", "Neecha Nagar" ] } } }, { $project: { _id: 0, title: 1, genres: 1 } }, { $unwind: { path: "$genres", preserveNullAndEmptyArrays: true } } ] )
[ { title: 'La porta del cielo' }, { title: 'Neecha Nagar' }, { genres: 'Animation', title: 'Brave' }, { genres: 'Adventure', title: 'Brave' }, { genres: 'Comedy', title: 'Brave' }, { genres: 'Action', title: 'Inception' }, { genres: 'Mystery', title: 'Inception' }, { genres: 'Sci-Fi', title: 'Inception' } ]
includeArrayIndex
La siguiente operación $unwind utiliza la opción includeArrayIndex para incluir el índice de la matriz en la salida.
db.movies.aggregate( [ { $match: { title: "Inception" } }, { $project: { _id: 0, title: 1, genres: 1 } }, { $unwind: { path: "$genres", includeArrayIndex: "genreIndex" } } ] )
[ { genres: 'Action', title: 'Inception', genreIndex: Long('0') }, { genres: 'Mystery', title: 'Inception', genreIndex: Long('1') }, { genres: 'Sci-Fi', title: 'Inception', genreIndex: Long('2') } ]
Agrupar por valores desglosados
El siguiente pipeline desenrolla el arreglo genres y agrupa los documentos resultantes por género para contar el número de películas en cada género:
db.movies.aggregate( [ // First Stage { $match: { title: { $in: [ "The Dark Knight", "Inception", "Interstellar", "Brave" ] } } }, // Second Stage { $project: { _id: 0, title: 1, genres: 1 } }, // Third Stage { $unwind: "$genres" }, // Fourth Stage { $group: { _id: "$genres", movieCount: { $sum: 1 } } }, // Fifth Stage { $sort: { movieCount: -1 } } ] )
[ { _id: 'Adventure', movieCount: 2 }, { _id: 'Action', movieCount: 2 }, { _id: 'Drama', movieCount: 2 }, { _id: 'Sci-Fi', movieCount: 2 }, { _id: 'Crime', movieCount: 1 }, { _id: 'Animation', movieCount: 1 }, { _id: 'Comedy', movieCount: 1 }, { _id: 'Mystery', movieCount: 1 } ]
Desplegar múltiple campos de arreglo
Puede aplicar $unwind múltiples veces en un solo pipeline para expandir documentos que contienen varios campos de arreglo. La siguiente operación desenrolla el arreglo genres y luego el arreglo cast para producir un documento plano para cada combinación de género y actor, luego agrupa por género para contar el total de apariciones del elenco en cada género:
db.movies.aggregate( [ // First Stage { $match: { title: { $in: [ "Inception", "The Dark Knight", "Interstellar" ] } } }, // Second Stage { $project: { _id: 0, title: 1, genres: 1, cast: 1 } }, // Third Stage { $unwind: "$genres" }, // Fourth Stage { $unwind: "$cast" }, // Fifth Stage { $group: { _id: "$genres", castAppearances: { $sum: 1 } } } ] )
[ { _id: 'Adventure', castAppearances: 4 }, { _id: 'Crime', castAppearances: 4 }, { _id: 'Action', castAppearances: 8 }, { _id: 'Drama', castAppearances: 8 }, { _id: 'Mystery', castAppearances: 4 }, { _id: 'Sci-Fi', castAppearances: 8 } ]
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 etapa $unwind a una canalización de agregación, llame al método Unwind() en un objeto PipelineDefinition.
El siguiente ejemplo crea una plataforma de pipeline que itera sobre el campo Genres en cada documento Movie de entrada. Para cada valor en el campo Genres, la plataforma crea un nuevo documento Movie y rellena su campo Genres con el valor Genres del documento de entrada.
var pipeline = new EmptyPipelineDefinition<Movie>() .Unwind(m => m.Genres);
Puedes usar un objeto AggregateUnwindOptions para personalizar el comportamiento del método Unwind().
El siguiente ejemplo realiza la misma operación que el ejemplo anterior, pero también incluye las siguientes opciones:
PreserveNullAndEmptyArraysasegura que los documentos que contienen un arreglo vacío en el campoGenresse incluyan en el resultado.La opción
IncludeArrayIndexagrega un nuevo campo llamadoIndexa cada documento de salida. El valor de este campo es el índice del valor del campoGenresen el arregloGenresdel documento de entrada.
var pipeline = new EmptyPipelineDefinition<Movie>() .Unwind(m => m.Genres, new AggregateUnwindOptions<Movie>() { PreserveNullAndEmptyArrays = true, IncludeArrayIndex = new ExpressionFieldDefinition<Movie, int>( m => m.Index) });
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 $unwind a una canalización de agregación, utilice el Operador $unwind en un objeto de canalización.
El siguiente ejemplo crea una plataforma de pipeline que itera sobre el campo genres en cada documento movie de entrada. Para cada valor en el campo genres, la plataforma crea un nuevo documento movie y rellena su campo genres con el valor genres del documento de entrada. A continuación, el ejemplo ejecuta el pipeline de agregación:
const pipeline = [{ $unwind: "$genres" }]; const cursor = collection.aggregate(pipeline); return cursor;
Puedes personalizar el comportamiento del método $unwind. El siguiente ejemplo realiza la misma operación que el ejemplo anterior, pero también incluye las siguientes opciones:
preserveNullAndEmptyArraysasegura que los documentos que contienen un arreglo vacío en el campogenresse incluyan en el resultado.includeArrayIndexañade un nuevo campo llamadoindexa cada documento de salida. El campo contiene el índice del arreglo del valorgenresen el campogenresdel documento de entrada.
const pipeline = [ { $unwind: { path: "$genres", preserveNullAndEmptyArrays: true, includeArrayIndex: "index" } } ]; const cursor = collection.aggregate(pipeline); return cursor;
Obtén más información
Para ver las etapas y expresiones relacionadas, consulte $group, $sum, $sort y $multiply.
Para ver un ejemplo completo, consulta el tutorial descomponer arreglos y agrupar datos.