2012-07-09 40 views
0

我有一個集合users在蒙戈和我執行這個地圖降低,我相信這是一個COUNT(*)GROUP BY的origin相當於:MongoDB的地圖減少數量給予更多的結果比查詢

> 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 

我缺少什麼?

+0

你可以顯示你的json對象嗎? – 2012-07-09 08:04:30

+0

這是一個行示例:http://pastebin.com/GhtJr9ES – giorgiosironi 2012-07-09 08:24:17

回答

1

您可以使用下面的地圖/減少的COUNT(*) GROUP BY origin

地圖當量/ Reduce函數:

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" 
}); 
+0

地圖縮小的結果已經正確;但find()與它不一致,因爲它發現各種來源的結果較少。 – giorgiosironi 2012-07-09 14:26:53

+0

你的意思是更少的結果?它沒有發出所有文件嗎? – 2012-07-09 15:34:46

+0

映射減少工作正常,但在原始表上執行db.users.find()或db.users.count()並沒有找到所有文檔 - 例如424代替449代表origin = 1。 – giorgiosironi 2012-07-09 15:46:22

2

使用的是稀疏索引萬一你的計數查詢?我唯一的猜測是,如果其他一些查詢標準導致索引中沒有文件被計數忽略,那麼就會有這種猜測。

我重新創建你的方案有一些固定數據和地圖/減少和簡單的計數查詢的結果是一致的:

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 
1

我有同樣的問題。我用reduce函數替換x.length by Array.sum(x)(假設你在map函數中發射1)並且它可以工作。我同意x.length應該工作,但我不能解釋爲什麼它不。