Map-Reduce 例子¶
在 mongo 命令行, db.collection.mapReduce() 方法封装了 mapReduce 命令。下面是一些使用 db.collection.mapReduce() 方法的例子:
接下来的map-reduce操作都是在集合 orders 上执行,集合中的文档格式类似于:
{
_id: ObjectId("50a8240b927d5d8b5891743c"),
cust_id: "abc123",
ord_date: new Date("Oct 04, 2012"),
status: 'A',
price: 25,
items: [ { sku: "mmm", qty: 5, price: 2.5 },
{ sku: "nnn", qty: 5, price: 2.5 } ]
}
计算每个顾客的总金额¶
首先在 orders 集合上按 cust_id 字段值执行分组map-reduce操作,并对每个分组内文档的 price 字段进行求和操作。
定义map方法来处理每一个输入文档:
在方法中,this 指的是当前 map-reduce 操作正在处理的文档。
该方法把每一个文档的 price 和 cust_id 字段映射为一对,并提交 cust_id 和 price 的配对。
var mapFunction1 = function() { emit(this.cust_id, this.price); };
定义对应的reduce函数,入参是 keyCustId 和 valuesPrices:
valuesPrices 字段是一个数组,保存了由map函数提交的按 keyCustId 分组的多个 price 值。
reduce函数最终对 valuesPrice 数组内的元素值执行求和运算。
var reduceFunction1 = function(keyCustId, valuesPrices) { return Array.sum(valuesPrices); };
使用 mapFunction1 方法和 reduceFunction1 方法对 orders 集合中的文档执行 map-reduce。
db.orders.mapReduce( mapFunction1, reduceFunction1, { out: "map_reduce_example" } )
本次操作的结果输出到 map_reduce_example 集合中。如果 map_reduce_example 集合已经存在,本次操作会把旧的记录覆盖。
计算订单总量和每种 sku 订购量的平均值¶
在这个例子中,会对集合 orders 中所有的 ord_date 大于 01/01/2012 的文档执行map-reduce操作。该操作对所有文档按 item.sku 字段的值进行分组,并计算订单总数和每种 sku 订购量的总和,同时也会计算每种 sku 的平均值。
定义map方法来处理每一个输入文档:
在方法中,this 指的是当前 map-reduce 操作正在处理的文档。
该方法逐个处理文档中的每个名目,为每个名目创建一个 sku 和 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); } };
定义相应的reduce函数,它使用两个参数 keySKU 和 countObjVals:
countObjVals 是一个数组字段,保存了从map函数提交给reduce函数的分组后的多个 keySKU 值。
该方法对 countObjVals 数组进行reduce,转换为一个单独的对象 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; };
定义一个使用两个参数 key 和 reducedVal 的结束函数。该函数在 reducedVal 中添加一个平均值 avg 字段,然后返回修改后的对象:
var finalizeFunction2 = function (key, reducedVal) { reducedVal.avg = reducedVal.qty/reducedVal.count; return reducedVal; };
在 orders 集合上执行使用了 mapFunction2, reduceFunction2, 和 finalizeFunction2 方法的 map-reduce 操作。
db.orders.mapReduce( mapFunction2, reduceFunction2, { out: { merge: "map_reduce_example" }, query: { ord_date: { $gt: new Date('01/01/2012') } }, finalize: finalizeFunction2 } )
本次操作使用了 query 字段来选择那些 ord_date 值大于 01/01/2012 的文档。然后把结果输出到集合 map_reduce_example 中。如果 map_reduce_example 已经存在,该输出会合并新的结果到集合中。