的$addToSet
運營商實際上只是另一種$group
,但只包含數組項結果。因此,要計算這些鍵的出現次數,只需對它們進行「分組」即可。第二$group
可以把它們放到一個數組:
db.hikes.aggregate([
// Group on distinct trail per hiker
{ "$group": {
"_id": {
"hiker": "$hiker_id",
"trail": "$trail"
},
"count": { "$sum": 1 }
}},
// Now roll-up per hiker and push to array
{ "$group": {
"_id": "$_id.hiker",
"trails": {
"$push": { "name": "$_id.trail", "count": "$count" }
}
}}
])
這給你的結果,如:
{
"_id": 123,
"trails": [
{ "name": "Dusty Peak", "count": 2 },
{ "name": "Windy Falls", "count": 1 },
{ "name": "Mushroom Alley", "count": 4 }
]
}
如果你仔細想想那時候真的所有你需要在第一$group
實際取得的成果管道階段,儘管每個徒步旅行者每個線索在一個文件中。所有第二個$group
正在做(實際上很快)只是通過將其餘信息添加到數組中來「捲起」每個遠足者的結果。
這是不一樣的你有什麼建議,但它的聚合框架做什麼。它不會以任何方式將「數據」轉換爲「鍵」。恕我直言,這是一件好事,因爲我不認爲代表數據點的「指定密鑰」是一個好主意。上面是乾淨的,很容易迭代爲一個自然數組。當然,所有需要的數據都在那裏。
如果真有你的心臟上tranforming到鍵設置,那麼上面仍然適用,最好是剛做的穿越 - 客戶端:
db.hikes.aggregate([
// Group on distinct trail per hiker
{ "$group": {
"_id": {
"hiker": "$hiker_id",
"trail": "$trail"
},
"count": { "$sum": 1 }
}},
// Now roll-up per hiker and push to array
{ "$group": {
"_id": "$_id.hiker",
"trails": {
"$push": { "name": "$_id.trail", "count": "$count" }
}
}}
]).forEach(function(doc) {
var newTrails = {};
doc.trails.forEach(function(trail) {
newTrails[trail.name] = trail.count;
});
doc.trails = newTrails;
printjson(doc);
})
或者基本上是類似的迭代器模式在任何語言實現您使用。
爲了記錄在案,這樣做的MapReduce的方法是:
db.hikes.mapReduce(
function() {
var data = {};
data[this.trail] = 1;
emit(this.hiker_id,data);
},
function(key,values) {
var result = {};
values.forEach(function(value) {
Object.keys(value).forEach(function(key) {
if (!result.hasOwnProperty(key))
result[key] = 0;
result[key] += value[key];
})
});
return result;
},
{ "out": { "inline": 1 } }
)
這在我的腦海裏是一種愚蠢的,因爲額外的「分組」依靠迭代對象鍵。其結果也有它自己的MapReduce的怪癖:
{
"_id": 123,
"value": {
"Dusty Peak": 2,
"Mushroom Alley": 4,
"Windy Falls": 1
}
}
還以爲是是服務器上的所有完成的,它不是沒有它的成本,而不是隻在JavaScript interpretaion。 mapReduce過程通常會多次調用reducer
函數,這意味着reducer的輸出實際上可能會在輸入(關鍵設計點)時結束。從這個角度來看,它意味着在連續傳遞時結果對象將「增長」,這意味着在迭代和測試密鑰的存在時會產生更多開銷。
備用匯總框架流程以更自然的方式處理此問題,並使用$group
數據收集中的高效算法進行處理。
我會建議在這裏分離您的問題。我會用$ addToSet進行更新,然後執行聚合管道並計算引用。 – jmugz3
我完全同意,這對我來說在語言層面很容易,但在Mongo層面上,我不確定語義。 –
如果您先執行$ addtoSet,那麼您可以進行彙總並使用$ sum來計算字段。 – jmugz3