Definição
$reduceAplica uma expressão para cada elemento em uma matriz e a combina em um único valor.
$reducetem a seguinte sintaxe:{ $reduce: { input: <array>, initialValue: <expression>, in: <expression>, as: <string>, valueAs: <string>, arrayIndexAs: <string> } } CampoTipoDescriçãoinputarray
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
nullou se referir a um campo ausente,$reducenullretornará.Se o argumento não se resolver em uma array ou
nullnem se referir a um campo ausente, retornará um$reduceerro.initialValueexpressão
O conjunto
valuecumulativo inicial antes deinser aplicado ao primeiro elemento da arrayinput.inexpressão
Uma expressão válida que
$reduceaplica a cada elemento na arrayinputna ordem da esquerda para a direita. Envolva o valorinputcom$reverseArraypara 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:asstring
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.
valueAsstring
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.
arrayIndexAsstring
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á$$myIndexna expressão.$$myIndexretorna o índice do elemento atual na arrayinput.Se você omitir
arrayIndexAs, você poderá utilizar a variável de sistema$$IDXna expressão para retornar o índice do elemento atual.Para obter exemplos, consulte Acessar o índice de cada item em uma array e Usar
$$IDXpara acessar o índice.Novidades na versão 8.3.
Se
inputse resolver em uma array vazia,$reduceretornaráinitialValue.
Exemplo | Resultados | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
| ||||||||||
|
| ||||||||||
|
|
Exemplos
Multiplicação
Probabilidade
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:
Use
$grouppara agrupar peloexperimentIde use$pushpara criar uma array com a probabilidade de cada evento.Use
$reducecom$multiplypara multiplicar e combinar os elementos deprobabilityArrem 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 }
Mercadoria com desconto
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 }
Concatenação de strings
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" }
Concatenação de arrays
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 } ] )
Cálculo de uma redução única
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 }
Cálculo de reduções múltiplas
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 }
Acesse o índice de cada item em uma array
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.
textcampo, 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 } ]
Use $$IDX para acessar o índice
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" ] } } } } } ] )