我想使用mapreduce来执行组聚合。这是我的地图功能:
function() {
emit(this.TransactionType, { Count: 1 });
}
这里有两个reduce函数:
function(key, values) {
var result = {Count: 0};
values.forEach(function(value) {
result.Count += 1;
});
return result;
}
function(key, values) {
var result = {Count: 0};
values.forEach(function(value) {
result.Count += value.Count;
});
return result;
}
这是两个结果:
"_id" : "A", "value" : { "Count" : 13.0 }
"_id" : "B", "value" : { "Count" : 2.0 }
"_id" : "C", "value" : { "Count" : 1.0 }
"_id" : "D", "value" : { "Count" : 209.0 }
"_id" : "E", "value" : { "Count" : 66.0 }
"_id" : "F", "value" : { "Count" : 11.0 }
"_id" : "G", "value" : { "Count" : 17.0 }
"_id" : "H", "value" : { "Count" : 17.0 }
"_id" : "A", "value" : { "Count" : 128.0 }
"_id" : "B", "value" : { "Count" : 115.0 }
"_id" : "C", "value" : { "Count" : 1.0 }
"_id" : "D", "value" : { "Count" : 3645.0 }
"_id" : "E", "value" : { "Count" : 1405.0 }
"_id" : "F", "value" : { "Count" : 256.0 }
"_id" : "G", "value" : { "Count" : 380.0 }
"_id" : "H", "value" : { "Count" : 398.0 }
那么,为什么这两个结果不同呢?
非常感谢
第一个reduce函数对每个值执行此操作:
result.Count += 1;
第二个这样做:
result.Count += value.Count;
因此,如果您的值列表是(1,2,3,4,5)
,那么第一个列表将为每个项添加+1,并将返回5作为输出。第二个将为每个项目添加+5(因为value.Count是5),因此它将输出5+5+5+5=25
result函数以{_id,[values]}的形式输出数据。对于reduce函数,输入可能如下:
"A", [{count:1}, {count:2}, {count:3}]
在第一个函数中,值数组中的每个文档的计数只会增加1,输出为:
"A", {count:3}
在第二个函数中,count的值将被相加,因此输出将是
"A", {count:6}
这就是你正在经历的。有关如何运行Map Reduce操作的逐步演练,请参阅MongoDB Cookbook食谱"使用版本化文档查找最大值和最小值"的"Extras"部分http://cookbook.mongodb.org/patterns/finding_max_and_min/
祝你好运,地图还原快乐!
将"reduce"函数视为"fold"高阶函数是很有帮助的。也就是说,您的"reduce"函数将应用于值列表和累积的对象(示例中的"result"变量),该对象最初是指定的,但最终将被函数的连续调用的输出所取代。更重要的是,将应用函数的值列表可以按任何顺序分解为任何数量的子列表!
例如,考虑使用JavaScript数组"reduce"函数时函数的行为,该函数是"fold"高阶函数的一个示例。第一个示例的行为不正确,因为它没有使用每个元素的"Count"属性。将其与Array#reduce一起使用的连续尝试将类似地失败:
function badReducer(accum, x) {
accum.Count += 1;
return accum;
}
var sum = {Count:0};
sum = [{Count:1}, {Count:2}, {Count:3}].reduce(badReducer, sum);
sum; // => {Count:3}, d'oh!
sum = [{Count:4}].reduce(badReducer, sum);
sum; // => {Count:5}, d'oh!
然而,您的第二个示例正确地添加了"Count"属性,并且可以连续应用于自己的输出:
function goodReducer(accum, x) {
accum.Count += x.Count;
return accum;
}
var sum = {Count:0};
sum = [{Count:1}, {Count:2}, {Count:3}].reduce(goodReducer, sum);
sum; // => {Count:6}, woohoo!
sum = [{Count:4}].reduce(goodReducer, sum);
sum; // => {Count:10}, woohoo!