On this page本页内容
Starting in MongoDB 5.0, map-reduce is deprecated:从MongoDB 5.0开始,不推荐使用map-reduce:
$group
, $merge
, and others.$group
、$merge
等)重写map-reduce操作。$accumulator
and $function
aggregation operators, available starting in version 4.4. $accumulator
和$function
聚合运算符,从4.4版开始提供。For examples of aggregation pipeline alternatives to map-reduce, see:有关映射减少的聚合管道备选方案的示例,请参阅:
mapReduce
The mapReduce
command allows you to run map-reduce aggregation operations over a collection.mapReduce
命令允许您对集合运行map-reduce聚合操作。
Starting in version 4.4, MongoDB ignores the verbose option.从4.4版开始,MongoDB忽略了verbose
选项。
Starting in version 4.2, MongoDB deprecates:从4.2版开始,MongoDB不推荐:
sharded
选项进行map-reduce。要输出到分片集合,请首先创建分片集合。MongoDB 4.2也不赞成替换现有的分片集合。nonAtomic: false
选项的显式规范。The mapReduce
command has the following syntax:mapReduce
命令具有以下语法:
db.runCommand( {
mapReduce: <string>,
map: <string or JavaScript>,
reduce: <string or JavaScript>,
finalize: <string or JavaScript>,
out: <output>,
query: <document>,
sort: <document>,
limit: <number>,
scope: <document>,
jsMode: <boolean>,
verbose: <boolean>,
bypassDocumentValidation: <boolean>,
collation: <document>,
writeConcern: <document>,
comment: <any>
} )
The command takes the following fields as arguments:该命令将以下字段作为参数:
mapReduce | string |
|
map | JavaScript or String |
|
reduce | JavaScript or String |
|
out | string or document |
|
query | document |
|
sort | document |
|
limit | number |
|
finalize | JavaScript or String |
|
scope | document |
|
jsMode | boolean |
|
verbose | boolean |
|
bypassDocumentValidation | boolean |
|
collation | document |
collation: { locale: <string>, caseLevel: <boolean>, caseFirst: <string>, strength: <int>, numericOrdering: <boolean>, alternate: <string>, maxVariable: <string>, backwards: <boolean> }
|
writeConcern | document |
|
comment | any |
|
The following is a prototype usage of the 以下是mapReduce
command:mapReduce
命令的原型用法:
var mapFunction = function() { ... }; var reduceFunction = function(key, values) { ... }; db.runCommand( { mapReduce: <input-collection>, map: mapFunction, reduce: reduceFunction, out: { merge: <output-collection> }, query: <query> } )
Although 尽管mapReduce
uses JavaScript, most interactions with MongoDB do not use JavaScript but use an idiomatic driver in the language of the interacting application.mapReduce
使用JavaScript,但与MongoDB的大多数交互都不使用JavaScript而是使用交互应用程序语言中的惯用驱动程序。
map
Functionmap
函数要求The map
function is responsible for transforming each input document into zero or more documents. map
函数负责将每个输入文档转换为零个或多个文档。It can access the variables defined in the 它可以访问scope
parameter, and has the following prototype:scope
参数中定义的变量,并具有以下原型:
function() { ... emit(key, value); }
The map
function has the following requirements:map
函数有以下要求:
map
function, reference the current document as this
within the function.map
函数中,在函数中将当前文档引用为this
。map
function should not access the database for any reason.map
函数不应出于任何原因访问数据库。map
function should be pure, or have no impact outside of the function (i.e. side effects.)map
函数应该是纯函数,或者在函数之外没有影响(即副作用)map
function may optionally call emit(key,value)
any number of times to create an output document associating key
with value
.map
函数可以可选地调用emit(key,value)
任意次数,以创建将key
与value
关联的输出文档。Starting in MongoDB 4.4, mapReduce
no longer supports the deprecated BSON type JavaScript code with scope (BSON type 15) for its functions. The map
function must be either BSON type String (BSON type 2) or BSON type JavaScript (BSON type 13). To pass constant values which will be accessible in the map
function, use the scope
parameter.
map
function has been deprecated since version 4.2.1.map
函数使用带有scope
的JavaScript代码。The following map
function will call emit(key,value)
either 0 or 1 times depending on the value of the input document's status
field:
function() { if (this.status == 'A') emit(this.cust_id, 1); }
The following map
function may call emit(key,value)
multiple times depending on the number of elements in the input document's items
field:
function() { this.items.forEach(function(item){ emit(item.sku, 1); }); }
reduce
FunctionThe reduce
function has the following prototype:
function(key, values) { ... return result; }
The reduce
function exhibits the following behaviors:
reduce
function should not access the database, even to perform read operations.reduce
function should not affect the outside system.reduce
function for a key that has only a single value. The values
argument is an array whose elements are the value
objects that are "mapped" to the key
.reduce
function more than once for the same key. In this case, the previous output from the reduce
function for that key will become one of the input values to the next reduce
function invocation for that key.reduce
function can access the variables defined in the scope
parameter.reduce
must not be larger than half of MongoDB's maximum BSON document size. This requirement may be violated when large documents are returned and then joined together in subsequent reduce
steps.Starting in MongoDB 4.4, mapReduce
no longer supports the deprecated BSON type JavaScript code with scope (BSON type 15) for its functions. The reduce
function must be either BSON type String (BSON type 2) or BSON type JavaScript (BSON type 13). To pass constant values which will be accessible in the reduce
function, use the scope
parameter.
reduce
function has been deprecated since version 4.2.1.Because it is possible to invoke the reduce
function more than once for the same key, the following properties need to be true:
value
emitted by the map
function.the reduce
function must be associative. The following statement must be true:
reduce(key, [ C, reduce(key, [ A, B ]) ] ) == reduce( key, [ C, A, B ] )
the reduce
function must be idempotent. Ensure that the following statement is true:
reduce( key, [ reduce(key, valuesArray) ] ) == reduce( key, valuesArray )
the reduce
function should be commutative: that is, the order of the elements in the valuesArray
should not affect the output of the reduce
function, so that the following statement is true:
reduce( key, [ A, B ] ) == reduce( key, [ B, A ] )
finalize
FunctionThe finalize
function has the following prototype:
function(key, reducedValue) { ... return modifiedObject; }
The finalize
function receives as its arguments a key
value and the reducedValue
from the reduce
function. Be aware that:
finalize
function should not access the database for any reason.finalize
function should be pure, or have no impact outside of the function (i.e. side effects.)finalize
function can access the variables defined in the scope
parameter.Starting in MongoDB 4.4, mapReduce
no longer supports the deprecated BSON type JavaScript code with scope (BSON type 15) for its functions. The finalize
function must be either BSON type String (BSON type 2) or BSON type JavaScript (BSON type 13). To pass constant values which will be accessible in the finalize
function, use the scope
parameter.
finalize
function has been deprecated since version 4.2.1.out
You can specify the following options for the 可以为out
parameter:out
参数指定以下选项:
This option outputs to a new collection, and is not available on secondary members of replica sets.此选项输出到新集合,并且在副本集的辅助成员上不可用。
out: <collectionName>
Starting in version 4.2, MongoDB deprecates:从4.2版开始,MongoDB不推荐:
sharded
选项进行map-reduce。nonAtomic: false
选项的显式规范。This option is only available when passing a collection that already exists to 此选项仅在将已存在的集合传递给out
. out
时可用。It is not available on secondary members of replica sets.它在副本集的辅助成员上不可用。
out: { <action>: <collectionName> [, db: <dbName>] [, sharded: <boolean> ] [, nonAtomic: <boolean> ] }
When you output to a collection with an action, the 当您使用操作输出到集合时,out
has the following parameters:out
具有以下参数:
<action>
: Specify one of the following actions::指定以下操作之一:
replace
Replace the contents of the 如果具有<collectionName>
if the collection with the <collectionName>
exists.<collectionName>
的集合存在,则替换<collecationName>
的内容。
merge
Merge the new result with the existing result if the output collection already exists. 如果输出集合已存在,则将新结果与现有结果合并。If an existing document has the same key as the new result, overwrite that existing document.如果现有文档与新结果具有相同的键,则覆盖该现有文档。
reduce
Merge the new result with the existing result if the output collection already exists. 如果输出集合已存在,请将新结果与现有结果合并。If an existing document has the same key as the new result, apply the 如果现有文档与新结果具有相同的键,请将reduce
function to both the new and the existing documents and overwrite the existing document with the result.reduce
函数应用于新文档和现有文档,并用结果覆盖现有文档。
db
:
Optional. 可选。The name of the database that you want the map-reduce operation to write its output. 希望map-reduce操作写入其输出的数据库的名称。By default this will be the same database as the input collection.默认情况下,这将是与输入集合相同的数据库。
sharded
:
Starting in version 4.2, the use of the 从4.2版开始,不推荐使用sharded
option is deprecated.sharded
选项。
Optional. 可选。If 如果为true
and you have enabled sharding on output database, the map-reduce operation will shard the output collection using the _id
field as the shard key.true
,并且您已经在输出数据库上启用了分片,则map-reduce操作将使用_id
字段作为分片键来分片输出集合。
If 如果true
and collectionName
is an existing unsharded collection, map-reduce fails.true
且collectionName
是现有的未共享集合,则map-reduce失败。
nonAtomic
:
Starting in MongoDB 4.2, explicitly setting 从MongoDB 4.2开始,不推荐将nonAtomic
to false
is deprecated.nonAtomic
显式设置为false
。
Optional. 可选。Specify output operation as non-atomic. 将输出操作指定为非原子操作。This applies only to the 这仅适用于merge
and reduce
output modes, which may take minutes to execute.merge
和reduce
输出模式,这可能需要几分钟的时间才能执行。
By default nonAtomic
is false
, and the map-reduce operation locks the database during post-processing.
If nonAtomic
is true
, the post-processing step prevents MongoDB from locking the database: during this time, other clients will be able to read intermediate states of the output collection.
Perform the map-reduce operation in memory and return the result. 在内存中执行map reduce操作并返回结果。This option is the only available option for 此选项是复制副本集辅助成员上out
on secondary members of replica sets.out
唯一可用的选项。
out: { inline: 1 }
The result must fit within the maximum size of a BSON document.结果必须符合BSON文档的最大大小。
If your MongoDB deployment enforces authentication, the user executing the 如果MongoDB部署强制身份验证,则执行mapReduce
command must possess the following privilege actions:mapReduce
e命令的用户必须拥有以下权限操作:
Map-reduce with {out : inline}
output option:
Map-reduce with the replace
action when outputting to a collection:
Map-reduce with the merge
or reduce
actions when outputting to a collection:
The readWrite
built-in role provides the necessary permissions to perform map-reduce aggregation.
MongoDB drivers automatically set afterClusterTime for operations associated with causally consistent sessions. Starting in MongoDB 4.2, the mapReduce
command no longer support afterClusterTime. As such, mapReduce
cannot be associatd with causally consistent sessions.
In mongosh
, the db.collection.mapReduce()
method is a wrapper around the mapReduce
command. The following examples use the db.collection.mapReduce()
method:
The examples in this section include aggregation pipeline alternatives without custom aggregation expressions. For alternatives that use custom expressions, see Map-Reduce to Aggregation Pipeline Translation Examples.
Create a sample collection orders
with these documents:
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" } ])
Perform the map-reduce operation on the orders
collection to group by the cust_id
, and calculate the sum of the price
for each cust_id
:
Define the map function to process each input document:定义映射函数以处理每个输入文档:
this
refers to the document that the map-reduce operation is processing.this
引用map-reduce操作正在处理的文档。price
to the cust_id
for each document and emits the cust_id
and price
.var mapFunction1 = function() { emit(this.cust_id, this.price); };
Define the corresponding reduce function with two arguments 使用两个参数keyCustId
and valuesPrices
:keyCustId
和valuesPrices
定义相应的reduce函数:
valuesPrices
is an array whose elements are the price
values emitted by the map function and grouped by keyCustId
.valuesPrice
array to the sum of its elements.var reduceFunction1 = function(keyCustId, valuesPrices) { return Array.sum(valuesPrices); };
Perform map-reduce on all documents in the 使用orders
collection using the mapFunction1
map function and the reduceFunction1
reduce function:mapFunction1
映射函数和reduceFunction1
-reduce函数对orders
集合中的所有文档执行映射缩减:
db.orders.mapReduce( mapFunction1, reduceFunction1, { out: "map_reduce_example" } )
This operation outputs the results to a collection named 此操作将结果输出到名为map_reduce_example
. map_reduce_example
的集合。If the 如果map_reduce_example
collection already exists, the operation will replace the contents with the results of this map-reduce operation.map_reduce_example
集合已经存在,则该操作将用此map-reduce操作的结果替换内容。
Query the map_reduce_example
collection to verify the results:
db.map_reduce_example.find().sort( { _id: 1 } )
The operation returns these documents:该操作将返回以下文档:
{ "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Busby Bee", "value" : 125 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Don Quis", "value" : 155 }
Using the available aggregation pipeline operators, you can rewrite the map-reduce operation without defining custom functions:使用可用的聚合管道运算符,您可以在不定义自定义函数的情况下重写map-reduce操作:
db.orders.aggregate([ { $group: { _id: "$cust_id", value: { $sum: "$price" } } }, { $out: "agg_alternative_1" } ])
The $group
stage groups by the cust_id
and calculates the value
field (See also $sum
). The value
field contains the total price
for each cust_id
.
The stage output the following documents to the next stage:
{ "_id" : "Don Quis", "value" : 155 } { "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Busby Bee", "value" : 125 }
$out
writes the output to the collection agg_alternative_1
. Alternatively, you could use $merge
instead of $out
.Query the 查询agg_alternative_1
collection to verify the results:agg_alternative_1
集合以验证结果:
db.agg_alternative_1.find().sort( { _id: 1 } )
The operation returns the following documents:该操作将返回以下文档:
{ "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Busby Bee", "value" : 125 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Don Quis", "value" : 155 }
For an alternative that uses custom aggregation expressions, see Map-Reduce to Aggregation Pipeline Translation Examples.有关使用自定义聚合表达式的备选方案,请参阅Map-Reduce到聚合管道转换示例。
In the following example, you will see a map-reduce operation on the 在下面的示例中,您将看到orders
collection for all documents that have an ord_date
value greater than or equal to 2020-03-01
.ord_date
值大于或等于2020-03-01
的所有文档的orders
集合上的map-reduce操作。
The operation in the example:示例中的操作:
item.sku
field, and calculates the number of orders and the total quantity ordered for each sku
.item.sku
字段分组,并计算每个sku
的订单数量和总订单数量。sku
value and merges the results into the output collection.sku
值的每个订单的平均数量,并将结果合并到输出集合中。When merging results, if an existing document has the same key as the new result, the operation overwrites the existing document. 合并结果时,如果现有文档与新结果具有相同的键,则该操作将覆盖现有文档。If there is no existing document with the same key, the operation inserts the document.如果没有具有相同键的现有文档,则该操作将插入该文档。
Example steps:
Define the map function to process each input document:定义映射函数以处理每个输入文档:
this
refers to the document that the map-reduce operation is processing.this
是指map reduce操作正在处理的文档。sku
with a new object value
that contains the count
of 1
and the item qty
for the order and emits the sku
(stored in the key
) and the 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); } };
Define the corresponding reduce function with two arguments 使用两个参数keySKU
and countObjVals
:keySKU
和countObjVals
定义相应的reduce函数:
countObjVals
keySKU
values passed by map function to the reducer function.keySKU
值的对象。countObjVals
array to a single object reducedValue
that contains the count
and the qty
fields.reducedVal
, the count
field contains the sum of the count
fields from the individual array elements, and the qty
field contains the sum of the qty
fields from the individual array elements.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; };
Define a finalize function with two arguments 定义一个带有两个参数key
and reducedVal
. key
和reducedVal
的finalize函数。The function modifies the 该函数修改reducedVal
object to add a computed field named avg
and returns the modified object:reducedVal
对象以添加名为avg的计算字段,并返回修改后的对象:
var finalizeFunction2 = function (key, reducedVal) { reducedVal.avg = reducedVal.qty/reducedVal.count; return reducedVal; };
Perform the map-reduce operation on the 使用orders
collection using the mapFunction2
, reduceFunction2
, and finalizeFunction2
functions:mapFunction2
、reduceFunction3
和finalizeFunction4
函数对orders
集合执行map-reduce操作:
db.orders.mapReduce( mapFunction2, reduceFunction2, { out: { merge: "map_reduce_example2" }, query: { ord_date: { $gte: new Date("2020-03-01") } }, finalize: finalizeFunction2 } );
This operation uses the query
field to select only those documents with ord_date
greater than or equal to new Date("2020-03-01")
. Then it outputs the results to a collection map_reduce_example2
.
If the 如果map_reduce_example2
collection already exists, the operation will merge the existing contents with the results of this map-reduce operation. map_reduce_example2
集合已经存在,则该操作将将现有内容与此map-reduce操作的结果合并。That is, if an existing document has the same key as the new result, the operation overwrites the existing document. 也就是说,如果现有文档具有与新结果相同的键,则该操作将覆盖现有文档。If there is no existing document with the same key, the operation inserts the document.如果没有具有相同键的现有文档,则该操作将插入该文档。
Query the 查询map_reduce_example2
collection to verify the results:map_reduce_example2
集合以验证结果:
db.map_reduce_example2.find().sort( { _id: 1 } )
The operation returns these documents:该操作将返回以下文档:
{ "_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 } }
Using the available aggregation pipeline operators, you can rewrite the map-reduce operation without defining custom functions:使用可用的聚合管道运算符,您可以在不定义自定义函数的情况下重写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" } } ] )
$match
stage selects only those documents with ord_date
greater than or equal to new Date("2020-03-01")
.$match
阶段仅选择ord_date
大于或等于new Date("2020-03-01")
的文档。The $unwind
stage breaks down the document by the items
array field to output a document for each array element. $unwind
阶段通过items
数组字段分解文档,为每个数组元素输出一个文档。For Example:例如:
{ "_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" } ...
The $group
stage groups by the items.sku
, calculating for each sku:
qty
field. The qty
field contains theqty
ordered per each items.sku
(See $sum
).orders_ids
array. The orders_ids
field contains an_id
's for the items.sku
(See $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 ] }
$project
stage reshapes the output document to mirror the map-reduce's output to have two fields _id
and value
. The $project
sets:The $unwind
stage breaks down the document by the items
array field to output a document for each array element. For Example:例如:
{ "_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" } ...
The $group
stage groups by the items.sku
, calculating for each sku:
qty
field. The qty
field contains the total qty
ordered per each items.sku
using $sum
.orders_ids
array. The orders_ids
field contains an array of distinct order _id
's for the items.sku
using $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 ] }
The $project
stage reshapes the output document to mirror the map-reduce's output to have two fields _id
and value
. The $project
sets:
value.count
to the size of the orders_ids
array using $size
.value.qty
to the qty
field of input document.value.avg
to the average number of qty per order using $divide
and $size
.{ "_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 } }
$merge
writes the output to the collection agg_alternative_3
. $merge
将输出写入集合agg_alternative_3
。_id
as the new result, the operation overwrites the existing document. _id
,则该操作将覆盖现有文档。Query the 查询agg_alternative_3
collection to verify the results:agg_alternative_3
集合以验证结果:
db.agg_alternative_3.find().sort( { _id: 1 } )
The operation returns the following documents:该操作将返回以下文档:
{ "_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 } }
For an alternative that uses custom aggregation expressions, see Map-Reduce to Aggregation Pipeline Translation Examples.有关使用自定义聚合表达式的备选方案,请参阅将Reduce映射到聚合管道转换示例。
For more information and examples, see the Map-Reduce page and Perform Incremental Map-Reduce.有关更多信息和示例,请参阅Map—Reduce页面和执行增量Map—Reduce。
If you set the out parameter to write the results to a collection, the 如果设置out参数以将结果写入集合,mapReduce
command returns a document in the following form:mapReduce
命令将返回以下格式的文档:
{ "result" : "map_reduce_example", "ok" : 1 }
{
"result" : <string or document>,
"timeMillis" : <int>,
"counts" : {
"input" : <int>,
"emit" : <int>,
"reduce" : <int>,
"output" : <int>
},
"ok" : <int>,
}
If you set the out parameter to output the results inline, the mapReduce
command returns a document in the following form:
{ "results" : [ { "_id" : <key>, "value" :<reduced or finalizedValue for key> }, ... ], "ok" : <int> }
{ "results" : [ { "_id" : <key>, "value" :<reduced or finalizedValue for key> }, ... ], "timeMillis" : <int>, "counts" : { "input" : <int>, "emit" : <int>, "reduce" : <int>, "output" : <int> }, "ok" : <int> }
mapReduce.results
For output written inline, an array of resulting documents. 对于内联写入的输出,生成的文档数组。Each resulting document contains two fields:每个结果文档包含两个字段:
_id
key
value,key
值,value
key
.key
的缩减或最终值。mapReduce.timeMillis
Available for MongoDB 4.2 and earlier only仅适用于MongoDB 4.2及更早版本
The command execution time in milliseconds.命令执行时间(毫秒)。
mapReduce.counts
Available for MongoDB 4.2 and earlier only仅适用于MongoDB 4.2及更早版本
Various count statistics from the mapReduce
command.mapReduce
命令中的各种计数统计信息。
mapReduce.counts.input
Available for MongoDB 4.2 and earlier only仅适用于MongoDB 4.2及更早版本
The number of input documents, which is the number of times the 输入文档数,即mapReduce
command called the map
function.mapReduce
命令调用map
函数的次数。
mapReduce.counts.emit
Available for MongoDB 4.2 and earlier only仅适用于MongoDB 4.2及更早版本
The number of times the mapReduce
command called the emit
function.mapReduce
命令调用emit
函数的次数。
mapReduce.counts.reduce
Available for MongoDB 4.2 and earlier only仅适用于MongoDB 4.2及更早版本
The number of times the mapReduce
command called the reduce
function.mapReduce
命令调用reduce
函数的次数。
mapReduce.counts.output
Available for MongoDB 4.2 and earlier only仅适用于MongoDB 4.2及更早版本
The number of output values produced.生成的输出值的数量。
mapReduce.ok
A value of 值为1
indicates the mapReduce
command ran successfully. 1
表示mapReduce
命令已成功运行。A value of 值为0
indicates an error.0
表示错误。
In addition to the aforementioned command specific return fields, the db.runCommand()
includes additional information:
$clusterTime
, and operationTime
.operationTime
and $clusterTime
.See db.runCommand Response for details on these fields.