Menu Docs
Página inicial do Docs
/
Manual 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

  • 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

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

booleano

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)