有效地计算MongoDB中出现的百分比

Yah*_*hel 3 php database mongodb

所以,我正在修补MongoDB,我正在尝试让count()聚合查询正确扩展,以便我可以轻松计算整个集合中文档中某些值的出现百分比.

我有一个结构如下的文档:

{
    foo : 'bar',
    moo : 'cow',
    values : {
        alpha : true,
        beta : false,
        gamma : false,
        delta : true ... (many more)
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我有几千个这样的文档,我想有效地计算values对象中所有值的真实百分比(或假的百分比)(在我的情况下,有~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)));
}
Run Code Online (Sandbox Code Playgroud)

但即使记录数量非常少(大约100个),这也需要9秒钟.

对此最好的方法是什么?

mst*_*arn 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}}
Run Code Online (Sandbox Code Playgroud)

当您插入主集合时,您也可以像这样执行upsert,这将为您提供数据的实时视图:

for (var key in this.values){
    db.counts.update({_id:key},
                     {$inc:{count:1, trues: (this.values[key] ? 1 : 0)}},
                     true);
}
Run Code Online (Sandbox Code Playgroud)

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