我正在尝试使用Map Reduce根据每个日期的某个字段值来计算数字文档。首先,这是一些常规find()函数的结果:
db.errors.find({ "cDate" : ISODate("2012-11-20T00:00:00Z") }).count();
返回579(即此日期有579份文件)
db.errors.find( { $and: [ { "cDate" : ISODate("2012-11-20T00:00:00Z") }, {"Type":"General"} ] } ).count()
返回443(即,此日期有443份文件,其中Type =“General”)
以下是我的MapReduce:
db.runCommand({ mapreduce: "errors",
map : function Map() {
emit(
this.cDate,//Holds a date value
{
count: 1,
countGeneral: 1,
Type: this.Type
}
);
},
reduce : function Reduce(key, values) {
var reduced = {count:0,countGeneral:0,Type:''};
values.forEach(function(val) {
reduced.count += val.count;
if (val.Type === 'General')
reduced.countGeneral += val.countGeneral;
});
return reduced;
},
finalize : function Finalize(key, reduced) {
return reduced;
},
query : { "cDate" : { "$gte" : ISODate("2012-11-20T00:00:00Z") } },
out : { inline : 1 }
});
对于日期20-11-20,地图减少了回报:
count: 579
countGeneral: 60 (should be 443 according to the above find query)
现在,我知道Reduce在循环方式上是不可预测的,所以我应该怎么做? 谢谢
答案 0 :(得分:1)
我建议你丢失其余的价值只是因为你没有在减少部分返回'一般'。
对于map
部分中发出并从reduce
函数返回的所有值,Reduce运行多次。
例如,当reduce的第一次迭代运行时,你的输出对象包含如下内容:
{count: 15, countGeneral: 3, Type: ''}
还有其他的reduce迭代会收集这个对象和其他像这样的对象,并且不会在那里看到Type:'General'
并且不再增加countGeneral
。
答案 1 :(得分:0)
您的地图功能有误。 你可以这样做:
function Map() {
var cG=0;
if (this.Type == 'General') { cG=1; }
emit(
this.cDate,//Holds a date value
{
count: 1,
countGeneral: cG
}
);
}
如果Type为'General',则发出countGeneral 1,否则为0。
然后你可以完全从你的emit函数中删除类型检查,因为你无论如何都要在reduce函数中销毁它。目前你的reduce clobbers在reduce阶段输入从emit传递的信息。