Docs 菜单

db.collection.mapReduce()

注意

作为 Map-Reduce 替代方案的聚合管道

从 MongoDB 5.0 开始, map-reduce已弃用:

  • 您应该使用聚合管道,而不是 map-reduce。聚合管道提供比 map-reduce 更好的性能和可用性。

  • 您可以使用聚合管道阶段(例如 $group$merge 等)重写 map-reduce 操作。

  • 对于需要自定义功能的 map-reduce 操作,可以使用 $accumulator$function 聚合操作符。可以使用这些操作符在 JavaScript 中定义自定义聚合表达式。

有关 map-reduce 的聚合管道替代方案的示例,请参阅:

db.collection.mapReduce(map,reduce, { <options> })

重要

mongosh 方法

本页面提供 mongosh 方法的相关信息。这不是数据库命令或特定语言驱动程序(例如 Node.js)的相关文档。

有关数据库命令,请参阅 mapReduce 命令。

如需了解 MongoDB API 驱动程序,请参阅特定语言的 MongoDB 驱动程序文档。

注意

视图不支持 map-reduce 操作。

此方法可用于以下环境中托管的部署:

重要

M0、M2、M5 和 Flex 集群不支持此命令。有关更多信息,请参阅不支持的命令。

注意

MongoDB ignores the verbose option.

从版本 4.2 开始,MongoDB 弃用了:

  • The map-reduce option to 创建 a new sharded collection as well as the use of the sharded option for map-reduce. To output to a sharded collection, create the sharded collection first. MongoDB 4.2 also deprecates the replacement of an existing sharded collection.

db.collection.mapReduce() 采用以下语法:

db.collection.mapReduce(
<map>,
<reduce>,
{
out: <collection>,
query: <document>,
sort: <document>,
limit: <number>,
finalize: <function>,
scope: <document>,
jsMode: <boolean>,
verbose: <boolean>,
bypassDocumentValidation: <boolean>
}
)

db.collection.mapReduce()接受以下参数:

Parameter
类型
说明

map

JavaScript 或字符串

A JavaScript function that associates or "maps" a value with a key and emits the key and value pair. You can specify the function as BSON 类型 JavaScript (BSON Type 13) or String (BSON Type 2).

See Requirements for the map Function for more information.

reduce

JavaScript 或字符串

A JavaScript function that "reduces" to a single object all the values associated with a particular key. You can specify the function as BSON type JavaScript (BSON Type 13) or String (BSON Type 2).

See Requirements for the reduce Function for more information.

options

文档

A document that specifies additional parameters to db.collection.mapReduce().

The following table describes additional arguments that db.collection.mapReduce() can accept.

字段
类型
说明

out

字符串或文档

Specifies the location of the result of the map-reduce operation. You can output to a collection, output to a collection with an action, or output inline. You may output to a collection when performing map-reduce operations on the primary members of the set; on 从节点 members you may only use the inline output.

See out Options for more information.

query

文档

Specifies the selection criteria using query operators for determining the documents input to the map function.

sort

文档

Sorts the 输入 documents. This option is useful for optimization. For example, specify the sort key to be the same as the emit key so that there are fewer reduce operations. The sort key must be in an existing index for this collection.

limit

数字

Specifies a maximum number of documents for the input into the map function.

finalize

Javascript or String

Optional. A JavaScript function that modifies the output after the reduce function. You can specify the function as BSON type JavaScript (BSON Type 13) or String (BSON Type 2).

See Requirements for the finalize Function for more information.

scope

文档

Specifies global variables that are accessible in the map, reduce and finalize functions.

jsMode

布尔

Specifies whether to convert intermediate data into BSON format between the execution of the map and reduce functions.

默认值为 false

如果为 false

  • 在内部,MongoDB 将 map 函数发出的 JavaScript 对象转换为 BSON 对象。然后,在调用 reduce 函数时,这些 BSON 对象会转换回 JavaScript 对象。

  • map-reduce 操作将中间 BSON 对象放置在临时磁盘存储中。这允许对任意大的数据集执行 map-reduce 操作。

如果为 true

  • 在内部,map 函数期间发出的 JavaScript 对象仍保留为 JavaScript 对象。无需转换 reduce 函数的对象,这可以提高执行速度。

  • 对于映射器 emit() 函数的 key 参数少于 500,000 个的结果集,只能使用jsMode

verbose

布尔

Specifies whether to include the timing information in the result information. Set verbose to true to include the timing information.

默认值为 false

This option is ignored. The result information always excludes the timing information. You can view timing information by running db.collection.explain() with db.collection.mapReduce() in the "executionStats" or "allPlansExecution" verbosity modes.

collation

文档

可选。

指定用于操作的排序规则

排序规则允许用户为字符串比较指定特定于语言的规则,例如字母大小写和重音符号规则。

排序规则选项的语法如下:

collation: {
locale: <string>,
caseLevel: <boolean>,
caseFirst: <string>,
strength: <int>,
numericOrdering: <boolean>,
alternate: <string>,
maxVariable: <string>,
backwards: <boolean>
}

指定排序规则时,locale 字段为必填字段;所有其他排序规则字段均为可选字段。有关字段的说明,请参阅排序规则文档

如果未指定排序规则,但集合具有默认排序规则(请参阅 db.createCollection()),则操作将使用为集合指定的排序规则。

如果没有为收集或操作指定排序规则,MongoDB 将使用先前版本中使用的简单二进制比较来进行字符串比较。

您不能为一个操作指定多个排序规则。例如,您不能为每个字段指定不同的排序规则,或者如果执行带排序的查找,则不能使用一种排序规则进行查找而另一种排序规则进行排序。

bypassDocumentValidation

布尔

可选。启用 mapReduce 可在此操作过程中绕过模式验证。这样就可以插入不符合验证要求的文档。

注意

map-reduce operations$where operator expressions cannot access certain global functions or properties, such as db, that are available in mongosh

The following JavaScript functions and properties are available to map-reduce operations and $where operator expressions:

可用属性
可用函数
args
MaxKey
MinKey
assert()
BinData()
DBPointer()
DBRef()
doassert()
emit()
gc()
HexData()
hex_md5()
isNumber()
isObject()
ISODate()
isString()
Map()
MD5()
NumberInt()
NumberLong()
ObjectId()
print()
printjson()
printjsononeline()
sleep()
Timestamp()
tojson()
tojsononeline()
tojsonObject()
UUID()
version()

map 函数负责将每个输入文档转换为零个或多个文档。它可以访问 scope 参数中定义的变量,并具有以下原型:

function() {
...
emit(key, value);
}

map 函数具有以下要求:

  • map 函数中,将当前文档引用为函数内的 this

  • map 函数不应 出于任何原因访问数据库。

  • map 函数应该是纯函数,或者对函数外部没有影响(即副作用)。

  • map 函数可以选择调用 emit(key,value) 任意次,以创建将 keyvalue 关联的输出文档。

以下 map 函数将调用 emit(key,value) 0 次或 1 次,具体取决于输入文档的 status 字段的值:

function() {
if (this.status == 'A')
emit(this.cust_id, 1);
}

以下 map 函数可能会多次调用 emit(key,value) ,具体取决于输入文档的 items 字段中的元素数量:

function() {
this.items.forEach(function(item){ emit(item.sku, 1); });
}

reduce 函数具有以下原型:

function(key, values) {
...
return result;
}

reduce 函数表现出以下行为:

  • reduce 函数不应访问数据库,即使是执行读操作也是如此。

  • reduce 函数不应 影响外部系统。

  • MongoDB 可以针对同一键多次调用 reduce 函数。在这种情况下,该键的 reduce 函数的先前输出将成为该键的下一个 reduce 函数调用的输入值之一。

  • reduce 函数可以访问 scope 参数中定义的变量。

  • reduce 的输入不得大于 MongoDB 最大 BSON 文档大小的一半。当返回大型文档并在后续的 reduce 步骤中将其连接在一起时,可能会违反此要求。

由于可以针对同一键多次调用 reduce 函数,因此以下属性必须为 true:

  • 返回对象的类型必须map 函数发出的 value 的类型相同

  • reduce 函数必须是关联函数。以下语句必须为 true:

    reduce(key, [ C, reduce(key, [ A, B ]) ] ) == reduce( key, [ C, A, B ] )
  • reduce 函数必须是幂等的。确保以下语句为 true:

    reduce( key, [ reduce(key, valuesArray) ] ) == reduce( key, valuesArray )
  • reduce 函数应该是可交换的:也就是说,valuesArray 中元素的顺序不应影响 reduce 函数的输出,因此以下语句成立:

    reduce( key, [ A, B ] ) == reduce( key, [ B, A ] )

您可以为 out 参数指定以下选项:

此选项输出到新集合,并且在副本集的从节点上不可用。

out: <collectionName>

注意

从版本 4.2 开始,MongoDB 弃用了:

  • The map-reduce option to 创建 a new sharded collection as well as the use of the sharded option for map-reduce. To output to a sharded collection, create the sharded collection first. MongoDB 4.2 also deprecates the replacement of an existing sharded collection.

仅当将已存在的集合传递给 out 时,此选项才可用。它不适用于副本集的从节点。

out: { <action>: <collectionName>
[, db: <dbName>]
[, sharded: <boolean> ] }

当使用操作输出到集合时,out 具有以下参数:

  • <action> :指定以下操作之一:

    • replace

      如果存在具有 <collectionName> 的集合,则替换 <collectionName> 的内容。

    • merge

      如果输出集合已经存在,则将新结果与现有结果合并。如果现有文档与新结果具有相同的键,则覆盖该现有文档。

    • reduce

      如果输出集合已经存在,则将新结果与现有结果合并。如果现有文档与新结果具有相同的键,请将 reduce 函数应用于新文档和现有文档,并使用结果覆盖现有文档。

  • db:

    可选。您希望 map-Reduce 操作写入其输出的数据库的名称。默认情况下,这将是与输入集合相同的数据库。

在内存中执行 map-reduce 操作并返回结果。此选项是副本集的从节点上 out 的唯一可用选项。

out: { inline: 1 }

结果必须符合 BSON 文档的最大大小

finalize 函数具有以下原型:

function(key, reducedValue) {
...
return modifiedObject;
}

finalize 函数接收 key 值和来自 reduce 函数的 reducedValue 作为其参数。请注意:

  • finalize 函数不应 出于任何原因访问数据库。

  • finalize 函数应该是纯函数,或者对函数外部没有影响(即副作用)。

  • finalize 函数可以访问 scope 参数中定义的变量。

本节中的示例包括不带自定义聚合表达式的聚合管道替代方案。有关使用自定义表达式的替代方案,请参阅Map-Reduce 到聚合管道转换示例。

创建一个包含以下文档的样本集合 orders

db.orders.insertMany([
{ _id: 1, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-01"), price: 25, items: [ { sku: "oranges", qty: 5, price: 2.5 }, { sku: "apples", qty: 5, price: 2.5 } ], status: "A" },
{ _id: 2, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-08"), price: 70, items: [ { sku: "oranges", qty: 8, price: 2.5 }, { sku: "chocolates", qty: 5, price: 10 } ], status: "A" },
{ _id: 3, cust_id: "Busby Bee", ord_date: new Date("2020-03-08"), price: 50, items: [ { sku: "oranges", qty: 10, price: 2.5 }, { sku: "pears", qty: 10, price: 2.5 } ], status: "A" },
{ _id: 4, cust_id: "Busby Bee", ord_date: new Date("2020-03-18"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },
{ _id: 5, cust_id: "Busby Bee", ord_date: new Date("2020-03-19"), price: 50, items: [ { sku: "chocolates", qty: 5, price: 10 } ], status: "A"},
{ _id: 6, cust_id: "Cam Elot", ord_date: new Date("2020-03-19"), price: 35, items: [ { sku: "carrots", qty: 10, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" },
{ _id: 7, cust_id: "Cam Elot", ord_date: new Date("2020-03-20"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },
{ _id: 8, cust_id: "Don Quis", ord_date: new Date("2020-03-20"), price: 75, items: [ { sku: "chocolates", qty: 5, price: 10 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" },
{ _id: 9, cust_id: "Don Quis", ord_date: new Date("2020-03-20"), price: 55, items: [ { sku: "carrots", qty: 5, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 }, { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" },
{ _id: 10, cust_id: "Don Quis", ord_date: new Date("2020-03-23"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }
])

针对 orders 集合执行 map-reduce 操作会按 cust_id 进行分组,并为每个 cust_id 计算 price 之和:

  1. 定义 Map 函数来处理每个输入文档:

    • 在函数中,this 指的是 Map-Reduce 操作正在处理的文档。

    • 该函数将每个文档的 price 映射到 cust_id,并输出 cust_idprice

    var mapFunction1 = function() {
    emit(this.cust_id, this.price);
    };
  2. 使用两个参数 keyCustIdvaluesPrices 定义相应的 Reduce 函数:

    • valuesPrices 是一个数组,其元素是由 Map 函数发出并按 keyCustId 分组的 price 值。

    • 该函数将 valuesPrice 数组缩减为其元素之和。

    var reduceFunction1 = function(keyCustId, valuesPrices) {
    return Array.sum(valuesPrices);
    };
  3. 使用 mapFunction1 Map 函数和 reduceFunction1 Reduce 函数对 orders 集合中的所有文档执行 Map-Reduce:

    db.orders.mapReduce(
    mapFunction1,
    reduceFunction1,
    { out: "map_reduce_example" }
    )

    此操作将结果输出到名为 map_reduce_example 的集合。如果 map_reduce_example 集合已存在,该操作将用此 Map-Reduce 操作的结果替换其内容。

  4. 查询 map_reduce_example 集合以验证结果:

    db.map_reduce_example.find().sort( { _id: 1 } )

    该操作会返回以下文档:

    { "_id" : "Ant O. Knee", "value" : 95 }
    { "_id" : "Busby Bee", "value" : 125 }
    { "_id" : "Cam Elot", "value" : 60 }
    { "_id" : "Don Quis", "value" : 155 }

利用可用的聚合管道操作符,您可以重写 Map-Reduce 操作,而无需定义自定义函数:

db.orders.aggregate([
{ $group: { _id: "$cust_id", value: { $sum: "$price" } } },
{ $out: "agg_alternative_1" }
])
  1. $group 阶段按 cust_id 分组并计算 value 字段(另见 $sum)。value 字段包含每个 cust_idprice 总额。

    此阶段将以下文档输出到下一阶段:

    { "_id" : "Don Quis", "value" : 155 }
    { "_id" : "Ant O. Knee", "value" : 95 }
    { "_id" : "Cam Elot", "value" : 60 }
    { "_id" : "Busby Bee", "value" : 125 }
  2. 然后,$out 将输出写入集合 agg_alternative_1。或者,你可以使用 $merge 代替 $out

  3. 查询 agg_alternative_1 集合以验证结果:

    db.agg_alternative_1.find().sort( { _id: 1 } )

    该操作将返回以下文档:

    { "_id" : "Ant O. Knee", "value" : 95 }
    { "_id" : "Busby Bee", "value" : 125 }
    { "_id" : "Cam Elot", "value" : 60 }
    { "_id" : "Don Quis", "value" : 155 }

另请参阅:

有关使用自定义聚合表达式的替代方案,请参阅 Map-Reduce 到聚合管道转换示例

在以下示例中,您将看到针对 ord_date 值大于或等于 2020-03-01 的所有文档对 orders 集合执行的 Map-Reduce 操作。

示例中的操作:

  1. item.sku 字段分组,计算每个 sku 的订单数量和总订购量。

  2. 计算每个 sku 值的每个订单的平均数量,并将结果合并到输出集合中。

合并结果时,如果现有文档与新结果具有相同的键,则该操作将覆盖现有文档。如果没有具有相同键的现有文档,操作将插入该文档。

步骤示例:

  1. 定义 Map 函数来处理每个输入文档:

    • 在函数中,this 指的是 Map-Reduce 操作正在处理的文档。

    • 对于每款商品,该函数将 sku 与新对象 value 关联,该对象包含 1count 和订单的商品 qty,并发出 sku(存储在 key 中)和 value

    var mapFunction2 = function() {
    for (var idx = 0; idx < this.items.length; idx++) {
    var key = this.items[idx].sku;
    var value = { count: 1, qty: this.items[idx].qty };
    emit(key, value);
    }
    };
  2. 使用两个参数 keySKUcountObjVals 定义相应的 Reduce 函数:

    • countObjVals 是一个数组,其元素是映射到分组 keySKU 值的对象,这些值由 Map 函数传递到 Reducer 函数。

    • 该函数将 countObjVals 数组缩减为包含 countqty 字段的单个对象 reducedValue

    • reducedVal 中,count 字段包含各个数组元素中 count 字段的总和,而 qty 字段包含各个数组元素中 qty 字段的总和。

    var reduceFunction2 = function(keySKU, countObjVals) {
    reducedVal = { count: 0, qty: 0 };
    for (var idx = 0; idx < countObjVals.length; idx++) {
    reducedVal.count += countObjVals[idx].count;
    reducedVal.qty += countObjVals[idx].qty;
    }
    return reducedVal;
    };
  3. 使用两个参数 keyreducedVal 定义 finalize 函数。该函数会修改 reducedVal 对象以添加名为 avg 的计算字段并返回修改后的对象:

    var finalizeFunction2 = function (key, reducedVal) {
    reducedVal.avg = reducedVal.qty/reducedVal.count;
    return reducedVal;
    };
  4. 使用 mapFunction2reduceFunction2finalizeFunction2 函数对 orders 集合执行 Map-Reduce 操作:

    db.orders.mapReduce(
    mapFunction2,
    reduceFunction2,
    {
    out: { merge: "map_reduce_example2" },
    query: { ord_date: { $gte: new Date("2020-03-01") } },
    finalize: finalizeFunction2
    }
    );

    此操作使用 query 字段来仅选择 ord_date 大于或等于 new Date("2020-03-01") 的文档。然后它将结果输出到集合 map_reduce_example2

    如果 map_reduce_example2 集合已存在,该操作会将现有内容与此 Map-Reduce 操作的结果合并。即,如果现有文档的键与新结果相同,则操作会覆盖现有文档。如果没有具有相同键的现有文档,操作将插入该文档。

  5. 查询 map_reduce_example2 集合以验证结果:

    db.map_reduce_example2.find().sort( { _id: 1 } )

    该操作会返回以下文档:

    { "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } }
    { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } }
    { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } }
    { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } }
    { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } }

利用可用的聚合管道操作符,您可以重写 Map-Reduce 操作,而无需定义自定义函数:

db.orders.aggregate( [
{ $match: { ord_date: { $gte: new Date("2020-03-01") } } },
{ $unwind: "$items" },
{ $group: { _id: "$items.sku", qty: { $sum: "$items.qty" }, orders_ids: { $addToSet: "$_id" } } },
{ $project: { value: { count: { $size: "$orders_ids" }, qty: "$qty", avg: { $divide: [ "$qty", { $size: "$orders_ids" } ] } } } },
{ $merge: { into: "agg_alternative_3", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } }
] )
  1. $match 阶段仅选择 ord_date 大于等于 new Date("2020-03-01") 的文档。

  2. $unwind 阶段按 items 数组字段对文档进行分解,为每个数组元素输出一个文档。例如:

    { "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 5, "price" : 2.5 }, "status" : "A" }
    { "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "apples", "qty" : 5, "price" : 2.5 }, "status" : "A" }
    { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "oranges", "qty" : 8, "price" : 2.5 }, "status" : "A" }
    { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" }
    { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" }
    { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "pears", "qty" : 10, "price" : 2.5 }, "status" : "A" }
    { "_id" : 4, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-18T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" }
    { "_id" : 5, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-19T00:00:00Z"), "price" : 50, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" }
    ...
  3. $group 阶段按 items.sku 分组,针对每个 sku 进行计算:

    • qty 字段。qty 字段包含
      每个 items.sku 的订购 qty 总计(参见 $sum)。
    • orders_ids 数组。orders_ids 字段包含一个
      items.sku 的不同顺序 _id 的数组(参见 $addToSet)。
    { "_id" : "chocolates", "qty" : 15, "orders_ids" : [ 2, 5, 8 ] }
    { "_id" : "oranges", "qty" : 63, "orders_ids" : [ 4, 7, 3, 2, 9, 1, 10 ] }
    { "_id" : "carrots", "qty" : 15, "orders_ids" : [ 6, 9 ] }
    { "_id" : "apples", "qty" : 35, "orders_ids" : [ 9, 8, 1, 6 ] }
    { "_id" : "pears", "qty" : 10, "orders_ids" : [ 3 ] }
  4. $project 阶段会重塑输出文档以镜像 Map-Reduce 的输出,使其具有两个字段 _idvalue$project 会:

  5. $unwind 阶段按 items 数组字段对文档进行分解,为每个数组元素输出一个文档。例如:

    { "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 5, "price" : 2.5 }, "status" : "A" }
    { "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "apples", "qty" : 5, "price" : 2.5 }, "status" : "A" }
    { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "oranges", "qty" : 8, "price" : 2.5 }, "status" : "A" }
    { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" }
    { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" }
    { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "pears", "qty" : 10, "price" : 2.5 }, "status" : "A" }
    { "_id" : 4, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-18T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" }
    { "_id" : 5, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-19T00:00:00Z"), "price" : 50, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" }
    ...
  6. $group 阶段按 items.sku 分组,针对每个 sku 进行计算:

    • qty 字段。qty 字段包含使用 $sum 为每个 items.sku 订购的 qty 总计。

    • orders_ids 数组。orders_ids 字段包含使用 $addToSetitems.sku 的不同顺序 _id 的数组。

    { "_id" : "chocolates", "qty" : 15, "orders_ids" : [ 2, 5, 8 ] }
    { "_id" : "oranges", "qty" : 63, "orders_ids" : [ 4, 7, 3, 2, 9, 1, 10 ] }
    { "_id" : "carrots", "qty" : 15, "orders_ids" : [ 6, 9 ] }
    { "_id" : "apples", "qty" : 35, "orders_ids" : [ 9, 8, 1, 6 ] }
    { "_id" : "pears", "qty" : 10, "orders_ids" : [ 3 ] }
  7. $project 阶段会重塑输出文档以镜像 Map-Reduce 的输出,使其具有两个字段 _idvalue$project 会:

    • 使用 $sizevalue.count 设置为 orders_ids 数组的大小

    • value.qty 设置为输入文档中的 qty 字段。

    • 使用 $divide$sizevalue.avg 设置为每个订单的平均数量

    { "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } }
    { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } }
    { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } }
    { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } }
    { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } }
  8. 最后,$merge 将输出写入集合 agg_alternative_3。如果现有文档的键 _id 与新结果相同,则操作会覆盖现有文档。如果没有具有相同键的现有文档,操作将插入该文档。

  9. 查询 agg_alternative_3 集合以验证结果:

    db.agg_alternative_3.find().sort( { _id: 1 } )

    该操作将返回以下文档:

    { "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } }
    { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } }
    { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } }
    { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } }
    { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } }

另请参阅:

有关使用自定义聚合表达式的替代方案,请参阅 Map-Reduce 到聚合管道转换示例

The output of the db.collection.mapReduce() method is identical to that of the mapReduce command. See the 输出 section of the mapReduce command for information on the db.collection.mapReduce() output.

db.collection.mapReduce() no longer supports afterClusterTime. As such, db.collection.mapReduce() cannot be associatd with causally consistent sessions.