實際上你可以在emit調用的第二個參數上傳遞任意對象。這意味着你可以利用這一點,並將用戶標識存儲在其中。例如,您的地圖功能可以是這樣的:
var mapFunc = function() {
if (this.track_redirect) {
var tempDoc = {};
tempDoc[this.track_userid] = 1;
emit(this.track_redirect, {
users_clicked: tempDoc,
total_clicks: 1
});
}
};
而且你的降低作用可能是這樣的:
var reduceFunc = function(key, values) {
var summary = {
users_clicked: {},
total_clicks: 0
};
values.forEach(function (doc) {
summary.total_clicks += doc.total_clicks;
// Merge the properties of 2 objects together
// (and these are actually the userids)
Object.extend(summary.users_clicked, doc.users_clicked);
});
return summary;
};
摘要對象的users_clicked財產基本上存儲每個用戶的ID作爲屬性(因爲你不能有重複的屬性,你可以保證它會存儲唯一的用戶)。還要注意,您必須注意傳遞給reduce函數的某些值可能是之前reduce的結果,上面的示例代碼考慮到了這一點。您可以在文檔here中找到有關上述行爲的更多信息。
爲了獲得獨特的計數,你可以通過在終結函數被調用時,減少階段完成:
var finalFunc = function(key, value) {
// Counts the keys of an object. Taken from:
// http://stackoverflow.com/questions/18912/how-to-find-keys-of-a-hash
var countKeys = function(obj) {
var count = 0;
for(var i in obj) {
if (obj.hasOwnProperty(i))
{
count++;
}
}
return count;
};
return {
redirect: key,
total_clicks: value.total_clicks,
unique_clicks: countKeys(value.users_clicked)
};
};
最後,您可以執行地圖縮小喜歡這份工作(修改out屬性來適合你的需求):
db.users.mapReduce(mapFunc, reduceFunc, { finalize: finalFunc, out: { inline: 1 }});
來源
2012-01-31 21:55:52
Ren
謝謝仁,那是完全正確的。這個例子很好的使用了我的數據 - 就像我現在真正理解的那樣!非常好的第一個stackoverflow答案matey! – joevallender 2012-02-01 09:46:27
如果有人在這個線程中發現了這個問題,這可能是有用的:我寫了Ren的答案,包括顯示每個階段之間的數據http://scriptogr.am/joevallender/post/simple-introduction-to-mapreduce-using-mongodb – joevallender 2012-06-14 12:53:03