Menu Docs
Página inicial do Docs
/ /

$reduce (operador de expressão )

$reduce

Aplica uma expressão para cada elemento em uma matriz e a combina em um único valor.

$reduce tem a seguinte sintaxe:

{
$reduce: {
input: <array>,
initialValue: <expression>,
in: <expression>,
as: <string>,
valueAs: <string>,
arrayIndexAs: <string>
}
}
Campo
Tipo
Descrição

input

array

Pode ser qualquerexpressão válida que resolva em uma array. Para mais informações sobre expressões, consulte Expressões.

Se o argumento se resolver em um valor de null ou se referir a um campo ausente, $reduce nullretornará.

Se o argumento não se resolver em uma array ou null nem se referir a um campo ausente, retornará um$reduce erro.

initialValue

expressão

O conjunto value cumulativo inicial antes de in ser aplicado ao primeiro elemento da array input.

in

expressão

Uma expressão válida que $reduce aplica a cada elemento na array input na ordem da esquerda para a direita. Envolva o valor input com $reverseArray para obter o equivalente à aplicação da expressão de combinação da direita para a esquerda.

Durante a avaliação da expressão in, duas variáveis estarão disponíveis:

  • value é a variável que representa o valor cumulativo da expressão.

  • this é a variável que se refere ao elemento que está sendo processado.

as

string

opcional. Um nome para a variável que representa cada elemento individual da array input. Se omitido, o nome da variável padrão será this.

Novidades na versão 8.3.

valueAs

string

opcional. Um nome para a variável que representa o valor cumulativo da expressão. Se omitido, o nome da variável padrão é value.

Novidades na versão 8.3.

arrayIndexAs

string

opcional. Um nome para a variável de agregação que representa o índice do elemento atual na array input. O primeiro índice do elemento da array é 0.

Você pode utilizar o nome da variável em uma expressão. Por exemplo, se você especificar arrayIndexAs: "myIndex", usará $$myIndex na expressão. $$myIndex retorna o índice do elemento atual na array input.

Se você omitir arrayIndexAs, você poderá utilizar a variável de sistema $$IDX na expressão para retornar o índice do elemento atual.

Para obter exemplos, consulte Acessar o índice de cada item em uma array e Usar $$IDX para acessar o índice.

Novidades na versão 8.3.

Se input se resolver em uma array vazia, $reduce retornará initialValue.

Exemplo
Resultados
{
$reduce: {
input: ["a", "b", "c"],
initialValue: "",
in: { $concat : ["$$value", "$$this"] }
}
}

"abc"

{
$reduce: {
input: [ 1, 2, 3, 4 ],
initialValue: { sum: 5, product: 2 },
in: {
sum: { $add : ["$$value.sum", "$$this"] },
product: { $multiply: [ "$$value.product", "$$this" ] }
}
}
}

{ "sum" : 15, "product" : 48 }

{
$reduce: {
input: [ [ 3, 4 ], [ 5, 6 ] ],
initialValue: [ 1, 2 ],
in: { $concatArrays : ["$$value", "$$this"] }
}
}

[ 1, 2, 3, 4, 5, 6 ]

Uma collection chamada events contém os eventos de um experimento de probabilidade. Cada experimento pode ter vários events, como rolar um dado várias vezes ou tirar várias cartas (sem reposição) em sucessão para obter um resultado desejado. Para obter a probabilidade global do experimento, precisaremos multiplicar a probabilidade de cada evento do experimento.

db.events.insertMany( [
{ _id : 1, type : "die", experimentId :"r5", description : "Roll a 5", eventNum : 1, probability : 0.16666666666667 },
{ _id : 2, type : "card", experimentId :"d3rc", description : "Draw 3 red cards", eventNum : 1, probability : 0.5 },
{ _id : 3, type : "card", experimentId :"d3rc", description : "Draw 3 red cards", eventNum : 2, probability : 0.49019607843137 },
{ _id : 4, type : "card", experimentId :"d3rc", description : "Draw 3 red cards", eventNum : 3, probability : 0.48 },
{ _id : 5, type : "die", experimentId :"r16", description : "Roll a 1 then a 6", eventNum : 1, probability : 0.16666666666667 },
{ _id : 6, type : "die", experimentId :"r16", description : "Roll a 1 then a 6", eventNum : 2, probability : 0.16666666666667 },
{ _id : 7, type : "card", experimentId :"dak", description : "Draw an ace, then a king", eventNum : 1, probability : 0.07692307692308 },
{ _id : 8, type : "card", experimentId :"dak", description : "Draw an ace, then a king", eventNum : 2, probability : 0.07843137254902 }
] )

Etapas:

  1. Use $group para agrupar pelo experimentId e use $push para criar uma array com a probabilidade de cada evento.

  2. Use $reduce com $multiply para multiplicar e combinar os elementos de probabilityArr em um único valor e projetá-lo.

db.probability.aggregate(
[
{
$group: {
_id: "$experimentId",
probabilityArr: { $push: "$probability" }
}
},
{
$project: {
description: 1,
results: {
$reduce: {
input: "$probabilityArr",
initialValue: 1,
in: { $multiply: [ "$$value", "$$this" ] }
}
}
}
}
]
)

A operação retorna o seguinte:

{ _id : "dak", results : 0.00603318250377101 }
{ _id : "r5", results : 0.16666666666667 }
{ _id : "r16", results : 0.027777777777778886 }
{ _id : "d3rc", results : 0.11764705882352879 }

Uma coleção chamada clothes contém os seguintes documentos:

db.clothes.insertMany( [
{ _id : 1, productId : "ts1", description : "T-Shirt", color : "black", size : "M", price : 20, discounts : [ 0.5, 0.1 ] },
{ _id : 2, productId : "j1", description : "Jeans", color : "blue", size : "36", price : 40, discounts : [ 0.25, 0.15, 0.05 ] },
{ _id : 3, productId : "s1", description : "Shorts", color : "beige", size : "32", price : 30, discounts : [ 0.15, 0.05 ] },
{ _id : 4, productId : "ts2", description : "Cool T-Shirt", color : "White", size : "L", price : 25, discounts : [ 0.3 ] },
{ _id : 5, productId : "j2", description : "Designer Jeans", color : "blue", size : "30", price : 80, discounts : [ 0.1, 0.25 ] }
] )

Cada documento contém uma array discounts contendo os cupons de desconto percentual atualmente disponíveis para cada item. Se cada desconto puder ser aplicado ao produto uma vez, podemos calcular o menor preço usando $reduce para aplicar a seguinte fórmula para cada elemento na array discounts: (1 - desconto) * preço.

db.clothes.aggregate(
[
{
$project: {
discountedPrice: {
$reduce: {
input: "$discounts",
initialValue: "$price",
in: { $multiply: [ "$$value", { $subtract: [ 1, "$$this" ] } ] }
}
}
}
}
]
)

A operação retorna o seguinte:

{ _id : ObjectId("57c893067054e6e47674ce01"), discountedPrice : 9 }
{ _id : ObjectId("57c9932b7054e6e47674ce12"), discountedPrice : 24.224999999999998 }
{ _id : ObjectId("57c993457054e6e47674ce13"), discountedPrice : 24.224999999999998 }
{ _id : ObjectId("57c993687054e6e47674ce14"), discountedPrice : 17.5 }
{ _id : ObjectId("57c993837054e6e47674ce15"), discountedPrice : 54 }

Uma coleção chamada people contém os seguintes documentos:

db.people.insertMany( [
{ _id : 1, name : "Melissa", hobbies : [ "softball", "drawing", "reading" ] },
{ _id : 2, name : "Brad", hobbies : [ "gaming", "skateboarding" ] },
{ _id : 3, name : "Scott", hobbies : [ "basketball", "music", "fishing" ] },
{ _id : 4, name : "Tracey", hobbies : [ "acting", "yoga" ] },
{ _id : 5, name : "Josh", hobbies : [ "programming" ] },
{ _id : 6, name : "Claire" }
] )

O exemplo a seguir reduz a array de strings hobbies a uma string bio única:

db.people.aggregate(
[
// Filter to return only non-empty arrays
{ $match: { "hobbies": { $gt: [ ] } } },
{
$project: {
name: 1,
bio: {
$reduce: {
input: "$hobbies",
initialValue: "My hobbies include:",
in: {
$concat: [
"$$value",
{
$cond: {
if: { $eq: [ "$$value", "My hobbies include:" ] },
then: " ",
else: ", "
}
},
"$$this"
]
}
}
}
}
}
]
)

A operação retorna o seguinte:

{ _id : 1, name : "Melissa", bio : "My hobbies include: softball, drawing, reading" }
{ _id : 2, name : "Brad", bio : "My hobbies include: gaming, skateboarding" }
{ _id : 3, name : "Scott", bio : "My hobbies include: basketball, music, fishing" }
{ _id : 4, name : "Tracey", bio : "My hobbies include: acting, yoga" }
{ _id : 5, name : "Josh", bio : "My hobbies include: programming" }

Uma coleção chamada matrices contém os seguintes documentos:

db.matrices.insertMany( [
{ _id : 1, arr : [ [ 24, 55, 79 ], [ 14, 78, 35 ], [ 84, 90, 3 ], [ 50, 89, 70 ] ] },
{ _id : 2, arr : [ [ 39, 32, 43, 7 ], [ 62, 17, 80, 64 ], [ 17, 88, 11, 73 ] ] },
{ _id : 3, arr : [ [ 42 ], [ 26, 59 ], [ 17 ], [ 72, 19, 35 ] ] },
{ _id : 4 }
] )

O exemplo a seguir recolhe os arrays bidimensionais em uma array collapsed única:

db.arrayconcat.aggregate(
[
{
$project: {
collapsed: {
$reduce: {
input: "$arr",
initialValue: [ ],
in: { $concatArrays: [ "$$value", "$$this" ] }
}
}
}
}
]
)

A operação retorna o seguinte:

{ _id : 1, collapsed : [ 24, 55, 79, 14, 78, 35, 84, 90, 3, 50, 89, 70 ] }
{ _id : 2, collapsed : [ 39, 32, 43, 7, 62, 17, 80, 64, 17, 88, 11, 73 ] }
{ _id : 3, collapsed : [ 42, 26, 59, 17, 72, 19, 35 ] }
{ _id : 4, collapsed : null }

O exemplo a seguir executa o mesmo recolhimento de array bidimensional do exemplo acima, mas também cria uma nova array contendo apenas o primeiro elemento de cada array.

db.arrayconcat.aggregate(
[
{
$project: {
results: {
$reduce: {
input: "$arr",
initialValue: [ ],
in: {
collapsed: {
$concatArrays: [ "$$value.collapsed", "$$this" ]
},
firstValues: {
$concatArrays: [ "$$value.firstValues", { $slice: [ "$$this", 1 ] } ]
}
}
}
}
}
}
]
)

A operação retorna o seguinte:

{ _id : 1, results : { collapsed : [ 24, 55, 79, 14, 78, 35, 84, 90, 3, 50, 89, 70 ], firstValues : [ 24, 14, 84, 50 ] } }
{ _id : 2, results : { collapsed : [ 39, 32, 43, 7, 62, 17, 80, 64, 17, 88, 11, 73 ], firstValues : [ 39, 62, 17 ] } }
{ _id : 3, results : { collapsed : [ 42, 26, 59, 17, 72, 19, 35 ], firstValues : [ 42, 26, 17, 72 ] } }
{ _id : 4, results : null }

Crie uma coleção de amostra denominada people com estes document:

db.people.insertMany( [
{ _id: 1, name: "Melissa", hobbies: [ "softball", "drawing", "reading" ] },
{ _id: 2, name: "Brad", hobbies: [ "gaming", "skateboarding" ] },
{ _id: 3, name: "Scott", hobbies: [ "basketball", "music", "fishing" ] },
{ _id: 4, name: "Tracey", hobbies: [ "acting", "yoga" ] },
{ _id: 5, name: "Josh", hobbies: [ "programming" ] },
{ _id: 6, name: "Claire" }
] )

O campo hobbies contém uma array dos hobbies de cada pessoa em ordem de classificação. O primeiro passatempo no array é o principal passatempo da pessoa em que a pessoa passa a maior parte do tempo. O primeiro passatempo tem um índice de array de 0.

O exemplo seguinte utiliza valueAs, as e arrayIndexAs. A variável myIndex tem o índice de cada passatempo na array hobbies. O exemplo retorna document com estes campos:

  • Nome da pessoa.

  • text campo, que inclui o nome do passatempo e a posição de cada passatempo na lista.

db.people.aggregate( [
{
$project: {
_id: 0,
name: 1,
text: {
$reduce: {
input: "$hobbies",
initialValue: "My hobbies include:",
valueAs: "accumulatedText",
as: "hobby",
arrayIndexAs: "myIndex",
in: {
$concat: [
"$$accumulatedText",
" ",
{ $toString: { $add: [ "$$myIndex", 1 ] } },
") ",
"$$hobby"
]
}
}
}
}
}
] )

Saída:

[
{ "name" : "Melissa", "text" : "My hobbies include: 1) softball 2) drawing 3) reading" }
{ "name" : "Brad", "text" : "My hobbies include: 1) gaming 2) skateboarding" }
{ "name" : "Scott", "text" : "My hobbies include: 1) basketball 2) music 3) fishing" }
{ "name" : "Tracey", "text" : "My hobbies include: 1) acting 2) yoga" }
{ "name" : "Josh", "text" : "My hobbies include: 1) programming" }
{ "name" : "Claire", "text" : null }
]

A variável $$IDX retorna o índice do elemento atual na array input. Você pode usar $$IDX se omitir o campo arrayIndexAs da expressão.

O exemplo a seguir retorna os mesmos documentos que o exemplo na seção anterior Acesse o índice de cada item em uma array, mas usa $$IDX em vez de arrayIndexAs:

db.people.aggregate( [
{
$project: {
_id: 0,
name: 1,
text: {
$reduce: {
input: "$hobbies",
initialValue: "My hobbies include:",
valueAs: "accumulatedText",
as: "hobby",
in: {
$concat: [
"$$accumulatedText",
" ",
{ $toString: { $add: [ "$$IDX", 1 ] } },
") ",
"$$hobby"
]
}
}
}
}
}
] )

Voltar

$rank

Nesta página