Menu Docs

Página inicial do DocsDesenvolver aplicaçõesManual do MongoDB

$unwind (agregação)

Nesta página

  • Definição
  • Compatibilidade
  • Sintaxe
  • Comportamentos
  • Exemplos
  • Recursos adicionais
$unwind

Desconstrói um campo de array a partir dos documentos de entrada para gerar um documento para cada elemento. Cada documento de saída é o documento de entrada com o valor do campo de array substituído pelo elemento.

Você pode utilizar o $unwind para implantações hospedadas nos seguintes ambientes:

  • MongoDB Atlas: o serviço totalmente gerenciado para implantações MongoDB na nuvem

Você pode passar um operando de caminho do campo ou um operando de documento para desdobrar um campo de array.

Você pode fornecer o caminho do campo de array para $unwind. Ao usar 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.

Você pode fornecer um documento para $unwind para especificar várias opções de comportamento.

{
$unwind:
{
path: <field path>,
includeArrayIndex: <string>,
preserveNullAndEmptyArrays: <boolean>
}
}
Campo
Tipo
Descrição
caminho
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 $ e coloque entre aspas.

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 $.

boleano

Opcional.

  • Se true, se path for nulo, estiver ausente ou for uma array vazia, $unwind gerará o documento.

  • Se false, se path for nulo, ausente ou uma array vazia, $unwind não gerará um documento.

O valor padrão é false.

  • Quando o operando não for um array, mas não estiver ausente, null ou um array vazio, $unwind trata o operando como um array que de um único elemento.

  • Quando o operando for null, ausente ou uma array vazia, $unwind segue o comportamento configurado para a opção preserveNullAndEmptyArrays .

Se você indicar um caminho de um campo inexistente ou de um array vazio no documento de entrada, $unwind, por padrão, ignorará o documento de entrada e não gerará 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 .

No mongosh, crie uma collection de amostra denominada inventory com o seguinte documento:

db.inventory.insertOne({ "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] })

A aggregation a seguir usa o estágio $unwind para gerar um documento para cada elemento da array sizes :

db.inventory.aggregate( [ { $unwind : "$sizes" } ] )

A operação retorna os seguintes resultados:

{ "_id" : 1, "item" : "ABC1", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "L" }

Cada documento é uma cópia exata documento de entrada, exceto pelo valor do campo sizes agora apresentando um array baseado no valor sizes original.

Considere a collection clothing:

db.clothing.insertMany([
{ "_id" : 1, "item" : "Shirt", "sizes": [ "S", "M", "L"] },
{ "_id" : 2, "item" : "Shorts", "sizes" : [ ] },
{ "_id" : 3, "item" : "Hat", "sizes": "M" },
{ "_id" : 4, "item" : "Gloves" },
{ "_id" : 5, "item" : "Scarf", "sizes" : null }
])

$unwind trata o campo sizes como uma array de elemento único se:

  • o campo está presente,

  • o valor não for nulo, e

  • o valor não é um array vazio.

Expanda as arrays sizes com $unwind:

db.clothing.aggregate( [ { $unwind: { path: "$sizes" } } ] )

A operação $unwind retorna:

{ _id: 1, item: 'Shirt', sizes: 'S' },
{ _id: 1, item: 'Shirt', sizes: 'M' },
{ _id: 1, item: 'Shirt', sizes: 'L' },
{ _id: 3, item: 'Hat', sizes: 'M' }
  • No documento "_id": 1, sizes é uma array preenchida. $unwind retorna um documento para cada elemento no campo sizes .

  • No documento, "_id": 3, sizes for resolvido para uma array de elemento único.

  • Documentos "_id": 2, "_id": 4 e "_id": 5 não retornam nada porque o campo sizes não pode ser reduzido a uma única array de elementos.

Observação

A sintaxe { path: <FIELD> } é opcional. As seguintes operações do $unwind são equivalentes.

db.clothing.aggregate( [ { $unwind: "$sizes" } ] )
db.clothing.aggregate( [ { $unwind: { path: "$sizes" } } ] )

Os exemplos preserveNullAndEmptyArrays e includeArrayIndex utilizam a seguinte collection:

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 }
])

A operação $unwind a seguir usa a opção preserveNullAndEmptyArrays para incluir documentos cujo campo sizes é nulo, ausente ou uma array vazia.

db.inventory2.aggregate( [
{ $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } }
] )

A saída inclui os documentos onde o campo sizes é nulo, ausente ou uma array vazia:

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

A seguinte operação do $unwind utiliza a opção includeArrayIndex para incluir o índice de array na saída.

db.inventory2.aggregate( [
{
$unwind:
{
path: "$sizes",
includeArrayIndex: "arrayIndex"
}
}])

A operação desenrola a array sizes e inclui o índice da array no novo campo arrayIndex. Se o campo sizes não resolver para uma array preenchida, mas não estiver ausente, nulo ou uma array vazia, o campo arrayIndex será 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 }

No mongosh, crie uma collection de amostra denominada inventory2 com os seguintes 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 }
])

O pipeline a seguir desenrola a array sizes e agrupa os documentos resultantes pelos valores de tamanho de desenrolamento:

db.inventory2.aggregate( [
// First Stage
{
$unwind: { path: "$sizes", preserveNullAndEmptyArrays: true }
},
// Second Stage
{
$group:
{
_id: "$sizes",
averagePrice: { $avg: "$price" }
}
},
// Third Stage
{
$sort: { "averagePrice": -1 }
}
] )
Primeiro estágio:

O estágio $unwind gera um novo documento para cada elemento da array sizes . O estágio usa a opção preserveNullAndEmptyArrays para incluir na saída os documentos em que o campo sizes está ausente, é nulo ou é uma array vazia. Este estágio passa os seguintes documentos para o próximo estágio:

{ "_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 }
Segundo estágio:

A etapa $group agrupa os documentos por sizes e calcula o preço médio de cada tamanho. Este estágio passa os seguintes documentos para o próximo estágio:

{ "_id" : "S", "averagePrice" : NumberDecimal("80") }
{ "_id" : "L", "averagePrice" : NumberDecimal("80") }
{ "_id" : "M", "averagePrice" : NumberDecimal("120") }
{ "_id" : null, "averagePrice" : NumberDecimal("45.25") }
Terceiro estágio:

O estágio $sort classifica os documentos por averagePrice em ordem decrescente. A operação retorna o seguinte resultado:

{ "_id" : "M", "averagePrice" : NumberDecimal("120") }
{ "_id" : "L", "averagePrice" : NumberDecimal("80") }
{ "_id" : "S", "averagePrice" : NumberDecimal("80") }
{ "_id" : null, "averagePrice" : NumberDecimal("45.25") }

Dica

Veja também:

No mongosh, crie uma collection de amostra denominada sales com os seguintes 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")
}
]
}
])

A operação a seguir agrupa os itens vendidos por suas marcações e calcula o valor total de vendas por cada marcação.

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" ] }
}
}
}
])
Primeira etapa

O primeiro estágio $unwind gera um novo documento para cada elemento da array 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

O segundo estágio $unwind gera um novo documento para cada elemento das arrays 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 } }
Terceiro estágio

O estágio $group agrupa os documentos pela tag e calcula o valor total de vendas de itens com cada tag:

{ "_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") }

Dica

Veja também:

← $unset (agregação)