Du kan faktiskt skicka ett godtyckligt objekt på den andra parametern i emit-anropet. Det betyder att du kan dra nytta av detta och lagra användar-id i det. Till exempel kan din kartfunktion se ut så här:
var mapFunc = function() {
if (this.track_redirect) {
var tempDoc = {};
tempDoc[this.track_userid] = 1;
emit(this.track_redirect, {
users_clicked: tempDoc,
total_clicks: 1
});
}
};
Och din reduceringsfunktion kan se ut så här:
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;
};
Egenskapen users_clicked för summary-objektet lagrar i princip varje användares id som en egenskap (eftersom du inte kan ha dubbletter av egenskaper kan du garantera att den lagrar unika användare). Observera också att du måste vara försiktig med att vissa av värdena som skickas till reduceringsfunktionen kan vara resultatet av en tidigare reducering och exempelkoden ovan tar hänsyn till det. Du kan hitta mer om nämnda beteende i dokumenten här .
För att få den unika räkningen kan du passera in finaliseringsfunktionen som anropas när reduceringsfasen är klar:
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)
};
};
Slutligen kan du utföra kartminskningsjobbet så här (ändra ut-attributet för att passa dina behov):
db.users.mapReduce(mapFunc, reduceFunc, { finalize: finalFunc, out: { inline: 1 }});