$reduce (aggregation)
Definition
$reduceApplies an expression to each element in an array and combines them into a single value.
$reducehas the following syntax:{ $reduce: { input: <array>, initialValue: <expression>, in: <expression> } } FieldTypeDescriptioninputarray
Can be any valid expression that resolves to an array. For more information on expressions, see Expression Operators.
If the argument resolves to a value of
nullor refers to a missing field,$reducereturnsnull.If the argument does not resolve to an array or
nullnor refers to a missing field,$reducereturns an error.initialValueexpression
The initial cumulative
valueset beforeinis applied to the first element of theinputarray.inexpression
A valid expression that
$reduceapplies to each element in theinputarray in left-to-right order. Wrap theinputvalue with$reverseArrayto yield the equivalent of applying the combining expression from right-to-left.During evaluation of the
inexpression, two variables will be available:If
inputresolves to an empty array,$reducereturnsinitialValue.
Example  | Results  | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
 | 
  | ||||||||||
 | 
  | ||||||||||
 | 
  | 
Examples
Multiplication
Probability
A collection named events contains the events of a probability
experiment. Each experiment can have multiple events, such as
rolling a die several times or drawing several cards (without replacement)
in succession to achieve a desired result. In order to obtain the
overall probability of the experiment, we will need to multiply the
probability of each event in the experiment.
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 } ] ) 
Steps:
Use
$groupto group by theexperimentIdand use$pushto create an array with the probability of each event.Use
$reducewith$multiplyto multiply and combine the elements ofprobabilityArrinto a single value and project it.
db.probability.aggregate(   [     {       $group: {         _id: "$experimentId",         probabilityArr: { $push: "$probability" }       }     },     {       $project: {         description: 1,         results: {           $reduce: {             input: "$probabilityArr",             initialValue: 1,             in: { $multiply: [ "$$value", "$$this" ] }           }         }       }     }   ] ) 
The operation returns the following:
{ _id : "dak", results : 0.00603318250377101 } { _id : "r5", results : 0.16666666666667 } { _id : "r16", results : 0.027777777777778886 } { _id : "d3rc", results : 0.11764705882352879 } 
Discounted Merchandise
A collection named clothes contains the following documents:
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 ] } ] ) 
Each document contains a discounts array containing the currently
available percent-off coupons for each item. If each discount can be
applied to the product once, we can calculate the lowest price by using
$reduce to apply the following formula for each element in the
discounts array: (1 - discount) * price.
db.clothes.aggregate(   [     {       $project: {         discountedPrice: {           $reduce: {             input: "$discounts",             initialValue: "$price",             in: { $multiply: [ "$$value", { $subtract: [ 1, "$$this" ] } ] }           }         }       }     }   ] ) 
The operation returns the following:
{ _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 } 
String Concatenation
A collection named people contains the following documents:
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" } ] ) 
The following example reduces the hobbies array of strings into a single string
bio:
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"                ]              }            }          }        }      }    ] ) 
The operation returns the following:
{ _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" } 
Array Concatenation
A collection named matrices contains the following documents:
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 } ] ) 
Computing a Single Reduction
The following example collapses the two dimensional arrays into a single array collapsed:
db.arrayconcat.aggregate(   [     {       $project: {         collapsed: {           $reduce: {             input: "$arr",             initialValue: [ ],             in: { $concatArrays: [ "$$value", "$$this" ] }           }         }       }     }   ] ) 
The operation returns the following:
{ _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 } 
Computing a Multiple Reductions
The following example performs the same two dimensional array collapse as the example above, but also creates a new array containing only the first element of each array.
db.arrayconcat.aggregate(   [     {       $project: {         results: {           $reduce: {             input: "$arr",             initialValue: [ ],             in: {               collapsed: {                 $concatArrays: [ "$$value.collapsed", "$$this" ]               },               firstValues: {                 $concatArrays: [ "$$value.firstValues", { $slice: [ "$$this", 1 ] } ]               }             }           }         }       }     }   ] ) 
The operation returns the following:
{ _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 }