Vous pouvez en fait passer un objet arbitraire sur le deuxième paramètre de l'appel d'émission. Cela signifie que vous pouvez en profiter et y stocker l'ID utilisateur. Par exemple, votre fonction de carte peut ressembler à ceci :
var mapFunc = function() {
if (this.track_redirect) {
var tempDoc = {};
tempDoc[this.track_userid] = 1;
emit(this.track_redirect, {
users_clicked: tempDoc,
total_clicks: 1
});
}
};
Et votre fonction de réduction pourrait ressembler à ceci :
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;
};
La propriété users_clicked de l'objet de résumé stocke essentiellement l'identifiant de chaque utilisateur en tant que propriété (puisque vous ne pouvez pas avoir de propriétés en double, vous pouvez garantir qu'il stockera des utilisateurs uniques). Notez également que vous devez faire attention au fait que certaines des valeurs transmises à la fonction reduce peuvent être le résultat d'une réduction précédente et l'exemple de code ci-dessus en tient compte. Vous pouvez en savoir plus sur ledit comportement dans la documentation ici .
Afin d'obtenir le décompte unique, vous pouvez passer la fonction de finaliseur qui est appelée lorsque la phase de réduction est terminée :
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)
};
};
Enfin, vous pouvez exécuter le travail de réduction de carte comme ceci (modifiez l'attribut out pour l'adapter à vos besoins) :
db.users.mapReduce(mapFunc, reduceFunc, { finalize: finalFunc, out: { inline: 1 }});