$reduce (aggregation)

在本页面

Definition

  • $reduce
    • 3.4 版的新功能。

将表达式应用于数组中的每个元素,并将它们组合为单个值。

$reduce具有以下语法:

{
    $reduce: {
        input: <array>,
        initialValue: <expression>,
        in: <expression>
    }
}
FieldTypeDescription
inputarray可以是解析为数组的任何有效expression。有关表达式的更多信息,请参见Expressions


如果参数解析为null的值或引用缺少的字段,则$reduce返回null
如果自变量没有解析为数组或null,也没有引用缺少的字段,则$reduce返回错误。
| initialValue |表达式|在in之前设置的初始累积value应用于input数组的第一个元素。
| in |表达式|有效的expression,表示$reduce按从左到右的 Sequences 应用于input数组中的每个元素。将input值与$reverseArray换行,产生的效果等同于从右到左应用组合表达式。
在评估in表达式期间,将有两个变量可用:
valuevariable,代表表达式的累积值。
thisvariable,表示正在处理的元素。|

如果input解析为空数组,则$reduce返回initialValue

ExampleResults
{

$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: {
Importing:[[52],[53]],
initialValue: [ 1, 2],
in: { $concatArrays : ["$$value", "$$this"] }
}
}
[ 1, 2, 3, 4, 5, 6 ]

Examples

Multiplication

Probability

名为events的集合包含概率实验的事件。每个实验可以具有多个events,例如连续滚动模具或连续绘制几张卡片 (无需更换) 以获得理想的结果。为了获得实验的总体概率,我们需要将实验中每个事件的概率相乘。

{_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 :

  • 使用$groupexperimentId分组,然后使用$push创建具有每个事件概率的数组。

  • $reduce$multiply结合使用,可以将probabilityArr的元素相乘并将其组合为单个值并进行投影。

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

该操作返回以下内容:

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

Discounted Merchandise

名为clothes的集合包含以下文档:

{ "_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 ] }

每个文档都包含一个discounts数组,该数组包含每个项目当前可用的折价优惠券。如果每个折扣都可以一次应用于该产品,我们可以使用$reduce来对discounts数组中的每个元素应用以下公式来计算最低价格:(1-折扣)*价格。

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

该操作返回以下内容:

{ "_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

名为people的集合包含以下文档:

{ "_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" }

下面的示例将hobbies字符串数组简化为单个字符串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"
               ]
             }
           }
         }
       }
     }
   ]
)

该操作返回以下内容:

{ "_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

名为matrices的集合包含以下文档:

{ "_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 }

计算一次减价

以下示例将二维数组折叠为单个数组collapsed

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

该操作返回以下内容:

{ "_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 }

计算多重减法

下面的示例执行与上面的示例相同的二维数组折叠,但是还创建一个仅包含每个数组的第一个元素的新数组。

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

该操作返回以下内容:

{ "_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 }