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
Para desenrollar un campo de matriz, pase un operando de ruta de campo o un operando de documento.
Operando de ruta de campo
Puedes pasar la ruta del campo de matriz a $unwind. Con esta sintaxis, $unwind no genera un documento si el valor del campo es nulo, falta o es una matriz vacía.
{ $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.Si falta el valor,
null, o es un arreglo vacío,$unwindsigue la opción preserveNullAndEmptyArrays. Cuando se especificaincludeArrayIndexy se conserva el documento, el índice esnull.
Campo ausente
Si especifica una ruta para un campo que no existe en un documento de entrada o el campo es una matriz vacía, $unwind, por defecto, ignora el documento de entrada y no generará 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 su implementación autogestionada de MongoDB, consulte Cargar el conjunto de datos de ejemplo. Si realizó alguna modificación en las bases de datos de ejemplo, es posible que deba eliminarlas y volver a crearlas para ejecutar los ejemplos de esta página.
Desenrollar un arreglo
La siguiente agregación utiliza la etapa $unwind para generar un documento para cada elemento en la matriz 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 array original genres.
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 array con datos.$unwinddevuelve un documento para cada elemento.Los documentos
"La porta del cielo"y"Neecha Nagar"no tienen un campogenres, por lo que$unwindno devuelve ningún documento para ellos.
Nota
La sintaxis { path: <FIELD> } es opcional. Las siguientes operaciones $unwind son equivalentes.
db.<COLLECTION>.aggregate( [ { $unwind: "<FIELD>" } ] )
db.<COLLECTION>.aggregate( [ { $unwind: { path: "<FIELD>" } } ] )
preserveNullAndEmptyArrays e 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 proceso descompone el array 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 } ]
Desenrollar múltiples campos de matriz
Puedes aplicar $unwind varias veces en una sola secuencia para expandir documentos que contienen varios campos de matriz. La siguiente operación desenrolla la matriz genres y luego la matriz cast para producir un documento plano para cada combinación de género y actor, y 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 $unwind etapa a una canalización de agregación, llame al método Unwind() en un PipelineDefinition objeto.
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 etapas y expresiones relacionadas, consulte $group, $sum, $sort y $multiply.
Para ver un ejemplo completo, consulte el tutorial "Desenrollar matrices y agrupar datos".