Definição
- $reduce
- Aplica 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> - } - } CampoTipoDescriçã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 - nullou se referir a um campo ausente,- $reduce- nullretornará.- Se o argumento não se resolver em uma array ou - nullnem se referir a um campo ausente, retornará um- $reduceerro.- initialValue- expressão - O conjunto - valuecumulativo inicial antes de- inser aplicado ao primeiro elemento da array- input.- in- expressão - Uma expressão válida que - $reduceaplica a cada elemento na array- inputna ordem da esquerda para a direita. Envolva o valor- inputcom- $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:- 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 pelo- experimentIde use- $pushpara criar uma array com a probabilidade de cada evento.
- Use - $reducecom- $multiplypara multiplicar e combinar os elementos de- probabilityArrem 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 }