对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。

$reduce(表达式操作符)

$reduce

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

$reduce 通过以下语法实现:

{ $reduce: { input: <array expression>, initialValue: <expression>, in: <expression>, as: <string>, valueAs: <string>, arrayIndexAs: <string> }}
字段
类型
说明

input

阵列

可以是解析为数组的任何有效表达式。有关表达式的更多信息,请参阅表达式。

如果参数解析为 null 的值或指向缺失的字段,$reduce 返回 null。

如果参数未解析为数组或 null,也未指向缺失字段,则 $reduce 返回错误。

initialValue

表达式(expression)

在 in 之前设置的初始累积 value 将应用于 input 数组的第一个元素。

in

表达式(expression)

一个有效的表达式,$reduce 按从左到右的顺序应用于 input 数组中的每个元素。用 $reverseArray 包装 input 值,得出的结果等同于从右到左应用组合表达式。

计算 in 表达式期间,有两个变量可用:

  • value 是表示该表达式累积值的变量。

  • this 是指代当前所处理元素的变量。

as

字符串

可选.代表 input数组中每个元素的变量名称。如果省略,则变量名称默认为 this。

8.3版本新增。

valueAs

字符串

可选.表示表达式累积值的变量名称。如果省略,则变量名称默认为 value。

8.3版本新增。

arrayIndexAs

字符串

可选.聚合变量的名称,表示当前元素在 input 数组中的索引。第一个数组元素索引为 0。

您可以在表达式中使用变量名称。示例,如果指定 arrayIndexAs: "myIndex",则在表达式中使用 $$myIndex。$$myIndex 返回 input数组中当前元素的索引。

如果省略 arrayIndexAs,则可以在表达式中使用 $$IDX 系统变量来返回当前元素的索引。

有关示例,请参阅 访问数组中每个项目的索引 和 使用 $$IDX 访问索引。

8.3版本新增。

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

例子
结果
{ $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 ]

名为 events 的集合包含概率实验的事件。每个实验可以有多个 events,例如多次掷骰子或连续抽几张牌(无需更换)以达到所需的结果。为了获得实验的总体概率,我们需要将实验中每个事件的概率相乘。

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 }] )

步骤:

  1. 使用 $group 按 experimentId 进行分组,并使用 $push 创建一个包含每个事件概率的数组。

  2. 将 $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 }

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

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 ] }] )

每个文档均包含一个 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 }

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

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" }] )

以下示例将 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" }

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

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 }] )

以下示例会将二维数组折叠为单个数组 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 }

使用以下 document 创建名为 people 的示例集合:

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" }] )

hobbies字段包含每个人的爱好数组,按排名顺序排列。数组中的第一个爱好是此人花费最多时间的主节点 (primary node in the replica set)爱好。第一个爱好的数组索引为 0。

以下示例使用了 valueAs、as 和 arrayIndexAs。myIndex 变量包含 hobbies数组中每个爱好的索引。该示例返回包含这些document的字段:

  • 人员姓名。

  • text 字段,其中包括爱好名称以及每个爱好在列表中的位置。

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" ] } } } } }] )

输出:

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

$$IDX 变量返回 input 数组中当前元素的索引。如果省略表达式中的 arrayIndexAs字段,则可以使用 $$IDX。

以下示例返回与上一节访问数组中每个项目的索引中的示例相同的document,但使用 $$IDX 而不是 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" ] } } } } }] )
给本页内容打分

在此页面上