Php 有效统计MongoDB中的发生率

Php 有效统计MongoDB中的发生率,php,mongodb,database,Php,Mongodb,Database,因此,我正在修补MongoDB,并尝试使count()聚合查询适当扩展,以便轻松计算文档中某些值在整个集合中的出现百分比 我有一份结构如下的文件: { foo : 'bar', moo : 'cow', values : { alpha : true, beta : false, gamma : false, delta : true ... (many more) } } 现在,我有几千个这样的文

因此,我正在修补MongoDB,并尝试使
count()
聚合查询适当扩展,以便轻松计算文档中某些值在整个集合中的出现百分比

我有一份结构如下的文件:

{
    foo : 'bar',
    moo : 'cow',
    values : {
        alpha : true,
        beta : false,
        gamma : false,
        delta : true ... (many more)
    }
}
现在,我有几千个这样的文档,我想有效地计算
values
对象中所有值的true(或false)百分比(在我的例子中,有~50个)。也就是说,alpha为真、beta为真的时间百分比是多少,等等

我一开始很天真地使用了
count()
,但它似乎一次只允许一个查询,所以我就这样做了(使用PHP Mongo类,但它基本上只是一个常规的
count()
函数:

 $array_of_keys = array('alpha', 'beta', 'gamma', 'delta'...);
 for($i=0;$i<count($array_of_keys);$i++){
    $array_of_keys = [...]
    for($i=0;$i<count($array_of_keys);$i++){

$false  = intval($collection->count(array($array_of_keys[$i]=>false)));
$true  = intval($collection->count(array($array_of_keys[$i]=>true)));
}
$array\u of_key=数组('alpha','beta','gamma','delta'…);
对于($i=0;$ifalse));
$true=intval($collection->count(数组($array\u of_keys[$i]=>true));
}
但即使只有很少的记录(大约100条),这也需要9秒

最好的方法是什么

以下是一个简单的方法,可以满足您的需求:

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}}

事实上,你甚至可以结合这些方法。执行一次性MapReduce批处理作业以填充计数集合,然后使用upserts使其保持最新。

@msteam使用map reduce肯定有正确的想法。尽管(通常)map reduce不用于“实时”查询,但请不要这样做。若你们只是在计算真值,那个么保持一个“count”列是一个简单的方法。但是,如果您想要更大或更复杂的“汇总”,通常的方法是运行一个预定的map reduce;这适用于计划进程,而不是用户请求。但对于几十条记录来说,9秒意味着一天中有足够的时间来处理我需要的所有信息。
for (var key in this.values){
    db.counts.update({_id:key},
                     {$inc:{count:1, trues: (this.values[key] ? 1 : 0)}},
                     true);
}