Je kunt eigenlijk een willekeurig object doorgeven aan de tweede parameter van de emit-aanroep. Dat betekent dat u hiervan kunt profiteren en de gebruikers-ID erin kunt opslaan. Uw kaartfunctie kan er bijvoorbeeld als volgt uitzien:
var mapFunc = function() {
if (this.track_redirect) {
var tempDoc = {};
tempDoc[this.track_userid] = 1;
emit(this.track_redirect, {
users_clicked: tempDoc,
total_clicks: 1
});
}
};
En je reduceerfunctie kan er als volgt uitzien:
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;
};
De eigenschap user_clicked van het samenvattingsobject slaat in feite de id van elke gebruiker op als een eigenschap (aangezien u geen dubbele eigenschappen kunt hebben, kunt u garanderen dat het unieke gebruikers zal opslaan). Merk ook op dat u voorzichtig moet zijn met het feit dat sommige van de waarden die aan de reduceerfunctie worden doorgegeven, het resultaat kunnen zijn van een eerdere reducering en de bovenstaande voorbeeldcode houdt daar rekening mee. U kunt meer over het genoemde gedrag vinden in de documenten hier .
Om de unieke telling te krijgen, kunt u de finalizer-functie doorgeven die wordt aangeroepen wanneer de reductiefase is voltooid:
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)
};
};
Ten slotte kunt u de taak voor het verkleinen van de kaart als volgt uitvoeren (wijzig het attribuut out om aan uw behoeften te voldoen):
db.users.mapReduce(mapFunc, reduceFunc, { finalize: finalFunc, out: { inline: 1 }});