Map-Reduce转换到聚合管道
从4.4版本开始,MongoDB添加了$accumulator
和$function
aggregation运算符。这些运算符为用户提供了定义自定义聚合表达式的能力。使用这些操作,可以大致重写map-reduce表达式,如下表所示。
注意
可以使用聚合管道操作符(如$group、$merge等)重写各种map-reduce表达式,而不需要自定义函数。
例如,请参见map-reduce示例。
Map-Reduce到聚合管道转换表
这张表只是粗略的翻译。例如,该表显示了使用$project
的mapFunction
的近似转换。
然而,mapFunction逻辑可能需要额外的阶段,例如,如果逻辑包括对数组的迭代:
然后,聚合管道包括一个
$unwind
和一个$project
:$project
中的emit
字段可以被命名为其他名称。为了进行可视化比较,选择了字段名称emit。
Map-Reduce | Aggregation Pipeline |
---|---|
db.collection.mapReduce( <mapFunction>, <reduceFunction>, { query: <queryFilter>, sort: <sortOrder>, limit: <number>, finalize: <finalizeFunction>, out: <collection> } ) | db.collection.aggregate( [ { $match: <queryFilter> }, { $sort: <sortOrder> }, { $limit: <number> }, { $project: { emits: { k: <expression>, v: <expression> } } }, { $unwind: “$emits” }, { $group: { _id: “$emits.k”}, value: { $accumulator: { init: <initCode>, accumulate: <reduceFunction>, accumulateArgs: [ “$emit.v”], merge: <reduceFunction>, finalize: <finalizeFunction>, lang: “js” }} } }, { $out: <collection> } ] ) |
db.collection.mapReduce( <mapFunction>, <reduceFunction>, { query: <queryFilter>, sort: <sortOrder>, limit: <number>, finalize: <finalizeFunction>, out: { merge: <collection>, db: <db> } } ) | db.collection.aggregate( [ { $match: <queryFilter> }, { $sort: <sortOrder> }, { $limit: <number> }, { $project: { emits: { k: <expression>, v: <expression> } } }, { $unwind: “$emits” }, { $group: { _id: “$emits.k”}, value: { $accumulator: { init: <initCode>, accumulate: <reduceFunction>, accumulateArgs: [ “$emit.v”], merge: <reduceFunction>, finalize: <finalizeFunction>, lang: “js” }} } }, { $out: { db: <db>, coll: <collection> } } ] ) |
db.collection.mapReduce( <mapFunction>, <reduceFunction>, { query: <queryFilter>, sort: <sortOrder>, limit: <number>, finalize: <finalizeFunction>, out: { merge: <collection>, db: <db> } } ) | db.collection.aggregate( [ { $match: <queryFilter> }, { $sort: <sortOrder> }, { $limit: <number> }, { $project: { emits: { k: <expression>, v: <expression> } } }, { $unwind: “$emits” }, { $group: { _id: “$emits.k”}, value: { $accumulator: { init: <initCode>, accumulate: <reduceFunction>, accumulateArgs: [ “$emit.v”], merge: <reduceFunction>, finalize: <finalizeFunction>, lang: “js” }} } }, { $merge: { into: { db: <db>, coll: <collection>}, on: “_id” whenMatched: “replace”, whenNotMatched: “insert” } }, ] ) |
db.collection.mapReduce( <mapFunction>, <reduceFunction>, { query: <queryFilter>, sort: <sortOrder>, limit: <number>, finalize: <finalizeFunction>, out: { merge: <collection>, db: <db> } } ) | db.collection.aggregate( [ { $match: <queryFilter> }, { $sort: <sortOrder> }, { $limit: <number> }, { $project: { emits: { k: <expression>, v: <expression> } } }, { $unwind: “$emits” }, { $group: { _id: “$emits.k”}, value: { $accumulator: { init: <initCode>, accumulate: <reduceFunction>, accumulateArgs: [ “$emit.v”], merge: <reduceFunction>, finalize: <finalizeFunction>, lang: “js” }} } }, { $merge: { into: { db: <db>, coll: <collection> }, on: “_id” whenMatched: [ { $project: { value: { $function: { body: <reduceFunction>, args: [ “$_id”, [ “$value”, “$$new.value” ] ], lang: “js” } } } } ] whenNotMatched: “insert” } }, ] ) |
db.collection.mapReduce( <mapFunction>, <reduceFunction>, { query: <queryFilter>, sort: <sortOrder>, limit: <number>, finalize: <finalizeFunction>, out: { inline: 1 } } ) | db.collection.aggregate( [ { $match: <queryFilter> }, { $sort: <sortOrder> }, { $limit: <number> }, { $project: { emits: { k: <expression>, v: <expression> } } }, { $unwind: “$emits” }, { $group: { _id: “$emits.k”}, value: { $accumulator: { init: <initCode>, accumulate: <reduceFunction>, accumulateArgs: [ “$emit.v”], merge: <reduceFunction>, finalize: <finalizeFunction>, lang: “js” }} } } ] ) |
例子
可以使用聚合管道操作符(如$group
、$merge
等)重写各种map-reduce表达式,而不需要自定义函数。但是,为了说明目的,下面的例子提供了两种选择。
示例1
通过cust_id
对订单集合组执行以下map-reduce
操作,并计算每个cust_id
的价格总和:
**备选方案1:(推荐)**您可以重写操作到聚合管道,而不将map-reduce函数转换为等效的管道阶段:
**备选方案2:(仅为说明目的)**下面的聚合管道提供了各种map-reduce函数的转换,使用$accumulator
定义自定义函数:
首先,
$project
阶段输出带有emit字段的文档。emit字段是一个包含以下字段的文档:key
包含cust_id
文档的值value
包含price
文档的值
然后,
$group
使用$accumulator
操作符来添加发出的值:最后,
$out
将输出写入集合agg_alternative_2
。或者,您可以使用$merge
而不是$out
。
示例2
以下字段对orders
集合组的map-reduce操作,item.sku
并计算每个sku的订单数量和总订购量。然后,该操作将为每个sku值计算每个订单的平均数量,并将结果合并到输出集合中。
**备选方案1:(推荐)**您可以重写操作到聚合管道,而不将map-reduce函数转换为等效的管道阶段:
**备选方案2:(仅为说明目的)**下面的聚合管道提供了各种map-reduce函数的转换,使用$accumulator
定义自定义函数:
$match
阶段只选择那些ord_date大于或等于new Date("2020-03-01")的文档。$unwinds
阶段按items数组字段分解文档,为每个数组元素输出一个文档。例如:$project
阶段输出带有emit字段的文档。emit字段是一个包含以下字段的文档:key
包含items.sku
值value
包含具有qty
值和count
值的文档
$group
使用$accumulator
操作符来添加发出的计数和数量,并计算avg字段:最后,
$merge
将输出写入集合agg_alternative_4
。如果现有文档具有与新结果相同的键_id,则操作将覆盖现有文档。如果没有具有相同密钥的现有文档,操作将插入该文档。
也可以看看 聚合命令比较
译者:李冠飞
校对:
最后更新于