【问题标题】:MongoDB map reduce count giving more results than a queryMongoDB map减少计数提供比查询更多的结果
【发布时间】:2012-07-09 08:02:19
【问题描述】:

我在 Mongo 中有一个集合 users,我执行这个 map reduce,我认为它相当于 COUNT(*) GROUP BY origin

> m = function() { for (i in this.membership) {
... emit( this.membership[i].platform_profile.origin, 1 );
... }  }
function () {
    for (i in this.membership) {
        emit(this.membership[i].platform_profile.origin, 1);
    }
}
> r = function( id, values ) { var result = 0; 
... for ( var i = 0; i < values.length; i ++ ) { result += values[i];  }
... return result; }
function (id, values) {
    var result = 0;
    for (var i = 0; i < values.length; i++) {
        result += values[i];
    }
    return result;
}
> db.users.mapReduce(m, r, {out : { inline: 1}});
{
    "results" : [
        {
            "_id" : 0,
            "value" : 15
        },
        {
            "_id" : 1,
            "value" : 449
        },
    ...
}

但如果我尝试计算有多少文档将此字段设置为特定值(例如 1),我得到的结果会更少:

db.users.count({"membership.platform_profile.origin": 1});

424

我错过了什么?

【问题讨论】:

标签: mongodb


【解决方案1】:

您的计数查询是否有机会使用稀疏索引?我唯一的猜测是,如果其他一些查询条件导致索引中不存在的文档被忽略,那么计数将被忽略。

我使用一些固定数据重新创建了您的架构,并且 map/reduce 和简单计数查询之间的结果是一致的:

db.users.drop();

var map = function() {
    for (i in this.membership) {
        emit(this.membership[i].platform_profile.origin, 1);
    }
};

var reduce = function(id, values ) {
    var result = 0;
    for (var i = 0; i < values.length; i++) {
        result += values[i];
    }
    return result;
}

var origins = {1: "a", 2: "b", 3: "c", 4: "d"};

for (var i = 0; i < 1000; ++i) {
    var membership = [];

    for (var o in origins) {
        if (0 == i % o) {
            membership.push({ platform_profile: { origin: origins[o] }});
        }
    }

    db.users.save({ membership: membership });
}

db.users.mapReduce(map, reduce, {out: {inline: 1}}).results.forEach(function(result){
    print(result["_id"] + ": " + result["value"]);
});

for (var o in origins) {
    print(origins[o] + ": " + db.users.count({"membership.platform_profile.origin": origins[o]}));
}

这是输出:

$ mongo --quiet mr_count.js 
a: 1000
b: 500
c: 334
d: 250
a: 1000
b: 500
c: 334
d: 250

【讨论】:

    【解决方案2】:

    您可以使用以下 map/reduce 等效于 COUNT(*) GROUP BY origin

    映射/减少函数:

    map = function() {
        if(!this.membership) return;
    
        for (i in this.membership) {
            if(!this.membership[i].platform_profile || !this.membership[i].platform_profile.origin) return;
            emit(this.membership[i].platform_profile.origin, 1);
        }
    }
    
    reduce = function(key, values) {
        var count = 0;
    
        for (v in values) {
            count += values[v];
        }
        return count;
    }
    
    result = db.runCommand({
            "mapreduce" : "users", 
            "map" : map,
            "reduce" : reduce,
            "out" : "users_count"
    });
    

    【讨论】:

    • map reduce的结果已经正确;但 find() 与它不一致,因为它找到的各种来源的结果较少。
    • 结果更少是什么意思?它不是发出所有文件吗?
    • map reduce 工作正常,但在原始表上执行 db.users.find() 或 db.users.count() 并不能找到所有文档 - 例如 424 而不是 449原点=1。
    【解决方案3】:

    我遇到了同样的问题。我在reduce函数中替换了x.length by Array.sum(x)(假设您在map函数中发出1)并且它可以工作。我同意x.length 也应该工作,但我无法解释为什么它不工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多