Definição
Compatibilidade
Você pode utilizar o $unwind para implantações hospedadas nos seguintes ambientes:
- MongoDB Atlas: o serviço totalmente gerenciado para implantações do MongoDB na nuvem
MongoDB Enterprise: a versão autogerenciada e baseada em assinatura do MongoDB
MongoDB Community: uma versão com código disponível, de uso gratuito e autogerenciada do MongoDB
Sintaxe
Passe um operando de caminho do campo ou um operando de documento para desenrolar um campo de array .
Operando de caminho de campo
Você pode fornecer o caminho do campo de array para $unwind. Com essa sintaxe, $unwind não gera um documento se o valor do campo for nulo, ausente ou um array vazio.
{ $unwind: <field path> }
Quando você especifica o caminho do campo, prefixe o nome do campo com um sinal de dólar $ e coloque entre aspas.
Operando do documento com opções
Você pode passar um documento para $unwind para especificar opções.
{ $unwind: { path: <field path>, includeArrayIndex: <string>, preserveNullAndEmptyArrays: <boolean> } }
Campo | Tipo | Descrição |
|---|---|---|
string | Caminho do campo para um campo de array. Para especificar um caminho do campo, prefixe o nome do campo com um sinal de dólar | |
string | Opcional. O nome de um novo campo para manter o índice da array do elemento. O nome não pode começar com um sinal de dólar | |
booleano | Opcional.
O valor padrão é |
Comportamentos
Caminho do campo não está em formato de array
Quando o valor em path não resulta em uma array, $unwind se comporta da seguinte maneira:
Se o valor não estiver ausente, não
null, e não for uma array vazia,$unwindgerará um único documento usando o valor como está.Se
includeArrayIndexfor especificado, o índice será0para entradas de array enullpara entradas que não sejam de array. Documentos mais tarde na lista têm um índice maior que0.Se o valor estiver ausente,
nullou uma array vazia,$unwindseguirá a opção preserveNullAndEmptyArrays. QuandoincludeArrayIndexé especificado e o documento é preservado, o índice énull.
Campo ausente
Se você indicar um caminho de um campo inexistente ou de um campo vazio no documento de entrada, $unwind, o padrão é que o documento não processe nem emita documentos para esse documento de entrada.
Para gerar documentos onde o campo de array está ausente, é nulo ou é uma array vazia, use a opção preserveNullAndEmptyArrays.
Exemplos
Os exemplos nesta página usam dados do conjunto de dados de amostra sample_mflix. Para obter detalhes sobre como carregar esse conjunto de dados em sua implantação autogerenciada do MongoDB , consulte Carregar o conjunto de dados de amostra. Se você fez modificações nos bancos de dados de amostra, talvez seja necessário descartar e recriar os bancos de dados para executar os exemplos nesta página.
Array de unwind
A agregação a seguir usa o estágio $unwind para gerar um documento para cada elemento da array genres do documento de filme 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 saída é idêntico ao documento de entrada, exceto pelo valor do campogenres , que agora contém um único elemento da array genres original.
Valores ausentes ou não em formato de array
A agregação a seguir usa o estágio $unwind com quatro documentos de filme. Dois dos documentos ("La porta del cielo" e "Neecha Nagar") não têm um campogenres :
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' } ]
Nos documentos
"Brave"e"Inception",genresé uma array preenchida.$unwindretorna um documento para cada elemento.Os documentos
"La porta del cielo"e"Neecha Nagar"não têm um campogenres, portanto,$unwindnão retorna nenhum documento para eles.
Observação
A sintaxe { path: <FIELD> } é opcional. As seguintes operações do $unwind são equivalentes.
db.<COLLECTION>.aggregate( [ { $unwind: "<FIELD>" } ] )
db.<COLLECTION>.aggregate( [ { $unwind: { path: "<FIELD>" } } ] )
preserveNullAndEmptyArrays e includeArrayIndex
Os exemplos preserveNullAndEmptyArrays e includeArrayIndex utilizam documentos da coleção sample_mflix.movies.
preserveNullAndEmptyArrays
A seguinte operação $unwind utiliza a opção preserveNullAndEmptyArrays para incluir documentos cujo campo genres está ausente.
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
A seguinte operação $unwind utiliza a opção includeArrayIndex para incluir o índice de array na saída.
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 desenrolados
O pipeline a seguir desenrola a array genres e agrupa os documentos resultantes por gênero para contar o número de filmes em 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 } ]
Desenrolar vários campos de array
Você pode aplicar $unwind várias vezes em um único pipeline para expandir documentos que contenham vários campos de array. A operação a seguir desenrola a array genres e, em seguida, a array cast para produzir um documento plano para cada combinação de ator de gênero e, em seguida, agrupa por gênero para contar o total de aparições do elenco em 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 } ]
Os exemplos de C# nesta página utilizam o banco de dados sample_mflix a partir dos conjuntos de dados de amostra do Atlas. Para saber como criar um cluster MongoDB Atlas gratuito e carregar os conjuntos de dados de exemplo, consulte Introdução na documentação do driver MongoDB .NET/C#.
A seguinte classe Movie modela os documentos na collection 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; } }
Observação
ConventionPack para Pascal Case
As classes C# nesta página usam Pascal case para seus nomes de propriedade, mas os nomes de campo na coleção MongoDB usam Camel case. Para considerar essa diferença, você pode usar o seguinte código para registrar um ConventionPack quando o aplicativo iniciar:
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);
Para usar o driver MongoDB .NET/C# para adicionar um $unwind estágio a uma agregação pipeline, chame o método Unwind() em um PipelineDefinition objeto.
O exemplo a seguir cria um estágio de pipeline que itera sobre o campo Genres em cada documento de entrada Movie . Para cada valor no campo Genres , o estágio cria um novo documento Movie e preenche seu campo Genres com o valor Genres do documento de entrada.
var pipeline = new EmptyPipelineDefinition<Movie>() .Unwind(m => m.Genres);
Você pode usar um objeto AggregateUnwindOptions para personalizar o comportamento do método Unwind().
O exemplo a seguir executa a mesma operação que o exemplo anterior, mas também inclui as seguintes opções:
PreserveNullAndEmptyArraysgarante que documentos que contêm uma array vazia no campoGenressejam incluídos na saída.A opção
IncludeArrayIndexadiciona um novo campo denominadoIndexa cada documento de saída. O valor deste campo é o índice da array do valor do campoGenresna arrayGenresdo 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) });
Os exemplos do Node.js nesta página utilizam o banco de dados do sample_mflix a partir dos conjuntos de dados de amostra do Atlas. Para saber como criar um cluster gratuito do MongoDB Atlas e carregar os conjuntos de dados de exemplo, consulte Introdução na documentação do driver do MongoDB Node.js
Para usar o driver Node.js do MongoDB para adicionar um estágio $unwind a um pipeline de agregação , use o operador $unwind em um objeto de pipeline.
O exemplo a seguir cria um estágio de pipeline que itera sobre o campo genres em cada documento de entrada movie . Para cada valor no campo genres , o estágio cria um novo documento movie e preenche seu campo genres com o valor genres do documento de entrada. Em seguida, o exemplo executa o agregação pipeline:
const pipeline = [{ $unwind: "$genres" }]; const cursor = collection.aggregate(pipeline); return cursor;
Você pode personalizar o comportamento do método $unwind. O exemplo a seguir executa a mesma operação que o exemplo anterior, mas também inclui as seguintes opções:
preserveNullAndEmptyArraysgarante que documentos que contêm uma array vazia no campogenressejam incluídos na saída.includeArrayIndexadiciona um novo campo denominadoindexa cada documento de saída. O campo contém o índice da array do valorgenresno campogenresdo documento de entrada.
const pipeline = [ { $unwind: { path: "$genres", preserveNullAndEmptyArrays: true, includeArrayIndex: "index" } } ]; const cursor = collection.aggregate(pipeline); return cursor;
Saiba mais
Para estágios e expressões relacionados, consulte $group, $sum, $sort e $multiply.
Para obter um exemplo completo, consulte o tutorial Desenrole arrays e dados de grupo.