在下面的答案,我用一個簡單的數據與整個集合五份答覆設置工作:
> db.foo.find()
{ "_id" : ObjectId("4fba6b0c7c32e336fc6fd7d2"), "replies" : [ 1, 2, 3 ] }
{ "_id" : ObjectId("4fba6b157c32e336fc6fd7d3"), "replies" : [ 1, 2 ] }
,由於我們不是簡單地計算文件,db.collection.count()不會幫助我們。我們需要使用MapReduce來掃描每個文檔並聚合回覆數組的長度。考慮以下幾點:
db.foo.mapReduce(
function() { emit('totalReplies', { count: this.replies.length }); },
function(key, values) {
var result = { count: 0 };
values.forEach(function(value) {
result.count += value.count;
});
return result;
},
{ out: { inline: 1 }}
);
地圖功能(第一個參數)在整個收集運行和不變的密鑰下發射每個文檔中的回覆的數量。然後,Mongo會考慮所有發出的值並多次運行reduce函數(第二個參數)以合併(逐字減少)結果。希望這裏的代碼很簡單。如果您是映射/縮減新手,則需要注意的一點是reduce方法必須能夠處理自己的輸出。這在上面鏈接的MapReduce文檔中有詳細解釋。注意:如果你的收藏非常大,你可能不得不使用另一種輸出模式(例如收集輸出)。然而,inline
適用於小數據集。
最後,如果你使用的MongoDB 2.1+,我們可以利用Aggregation Framework,以避免寫JS的功能和更輕鬆地進行:
db.foo.aggregate(
{ $project: { replies: 1 }},
{ $unwind: "$replies" },
{ $group: {
_id: "result",
totalReplies: { $sum: 1 }
}}
);
三件事都發生在這裏。首先,我們告訴Mongo我們對replies
字段感興趣。其次,我們想展開數組,以便我們可以遍歷投影中各個字段的所有元素。最後,我們將在「結果」桶下(任何常量都可以)統計結果,將1
添加到每個迭代的totalReplies
結果中。執行該查詢將產生以下結果:
{
"result" : [{
"_id" : "result",
"totalReplies" : 5
}],
"ok" : 1
}
雖然我寫了關於蒙戈客戶端上面的答案,你應該沒有問題,將它們轉換到PHP。您需要使用MongoDB::command()來運行MapReduce或聚合查詢,因爲PHP驅動程序目前沒有輔助方法。目前PHP文檔中有一個MapReduce示例,您可以參考this Google group post以通過相同的方法執行聚合查詢。
您好,只是想知道怎麼會這樣應用於收集 – troy
您可以使用類似於我的例子聚合管道中的所有答覆從一個單一的文件算起,開始與['$ match'](http://docs.mongodb.org/manual/reference/aggregation/match/)一起縮小爲單個文檔;不過,我認爲最簡單的方法是簡單地選擇文檔並在應用程序中計算數組長度。如果您關心數據大小,可以從嵌入式文檔數組(例如'{respond.author}')投影單個字段,或者甚至丟失一個空字段以返回一個空對象數組(仍可計數) 。 – jmikola