所以,我正在修补MongoDB,我正在尝试让count()
聚合查询正确扩展,以便我可以轻松计算整个集合中文档中某些值的出现百分比。
我的文档结构如下:
{
foo : 'bar',
moo : 'cow',
values : {
alpha : true,
beta : false,
gamma : false,
delta : true ... (many more)
}
}
现在,我有几千个这样的文档,我想有效地计算values
对象中所有值的真实百分比(或假的百分比)(在我的情况下,有〜50)。即,alpha的时间百分比是多少,β是真的,等等。
我开始天真地使用count()
,但似乎它一次只允许一个查询,所以这导致我这样做(使用PHP Mongo类,但它基本上只是一个常规的{{1}功能:
count()
但即使记录数量非常少(大约100),这也需要9秒。
最好的方法是什么?
答案 0 :(得分:5)
这是一个简单的MapReduce,可以做你想做的事情:
map = function() {
for (var key in this.values){
emit(key, {count:1, trues: (this.values[key] ? 1 : 0)});
}
}
reduce = function(key, values){
var out = values[0];
for (var i=1; i < values.length; i++){
out.count += values[i].count;
out.trues += values[i].trues;
}
return out;
}
finalize = function(key, value){
value.ratio = value.trues / value.count;
return value;
}
db.runCommand({mapReduce:'collection',
map:map,
reduce:reduce,
finalize:finalize,
out:'counts'
})
db.counts.findOne({_id:'alpha'})
{_id: 'alpha', value: {count: 100, trues: 52, ratio: 0.52}}
当您插入主系列时,您也可以执行upsert这样的操作,这样可以实时查看您的数据:
for (var key in this.values){
db.counts.update({_id:key},
{$inc:{count:1, trues: (this.values[key] ? 1 : 0)}},
true);
}
事实上,您甚至可以将这些方法结合起来。执行一次性MapReduce批处理作业以填充计数集合,然后使用upserts使其保持最新。