我的数据库中有一个表示从各种来源提取的IP地址的集合。其示例如下所示:
{ "_id" : ObjectId("4e71060444dce16174378b79"), "ip" : "xxx.xxx.xxx.xxx", "sources" : { "Source1" : NumberLong(52), "Source2" : NumberLong(7) } }
每个对象都有一个或多个来源。
我的目标是显示每个来源报告的条目数,而不必知道每个可能来源的名称(因为可能随时添加新的来源)。我试图通过简单地为每个对象的源哈希中的每个键发出一个1来解决这个问题,但似乎我的语法出了问题。如果我执行以下操作:
var map_s = function(){
for(var source in this.sources) {
emit(source, 1);
}
}
var red_s = function(key, values){
var total = 0;
values.forEach(function(){
total++;
});
return total;
}
var op = db.addresses.mapReduce(map_s, red_s, {out: 'results'});
db.results.find().forEach(printjson);
我得到了
{ "_id" : "Source1", "value" : 12 }
{ "_id" : "Source2", "value" : 230 }
{ "_id" : "Source3", "value" : 358 }
{ "_id" : "Source4", "value" : 398 }
{ "_id" : "Source5", "value" : 39 }
{ "_id" : "Source6", "value" : 420 }
{ "_id" : "Source7", "value" : 156 }
这对于数据库大小来说太小了。例如,如果我计算一个特定的来源,我会在shell中得到以下内容:
> db.addresses.count({"sources.Source4": {$exists: true}});
1260538
我的错误在哪里?
答案 0 :(得分:1)
是的,您的reduce方法存在问题,它必须是幂等的。 请记住,reduce()可能会在中间结果上多次调用。
而不是
values.forEach(function(){
total++;
});
你需要:
values.forEach(function(x){
total += x;
});
答案 1 :(得分:0)
你可以分享你的地图代码并减少功能吗? 很可能在你的减少计数中存在一个错误。