Puoi effettivamente passare un oggetto arbitrario sul secondo parametro della chiamata emit. Ciò significa che puoi trarne vantaggio e archiviare l'ID utente al suo interno. Ad esempio, la funzione della tua mappa può assomigliare a questa:
var mapFunc = function() {
if (this.track_redirect) {
var tempDoc = {};
tempDoc[this.track_userid] = 1;
emit(this.track_redirect, {
users_clicked: tempDoc,
total_clicks: 1
});
}
};
E la tua funzione di riduzione potrebbe assomigliare a questa:
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 proprietà users_clicked dell'oggetto riepilogo memorizza sostanzialmente l'id di ogni utente come una proprietà (poiché non puoi avere proprietà duplicate, puoi garantire che memorizzerà utenti univoci). Si noti inoltre che è necessario prestare attenzione al fatto che alcuni dei valori passati alla funzione reduce possono essere il risultato di una riduzione precedente e il codice di esempio sopra ne tiene conto. Puoi trovare ulteriori informazioni su detto comportamento nei documenti qui .
Per ottenere il conteggio univoco, puoi passare la funzione finalizzatore che viene chiamata al termine della fase di riduzione:
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)
};
};
Infine, puoi eseguire il lavoro di riduzione della mappa in questo modo (modifica l'attributo out in base alle tue esigenze):
db.users.mapReduce(mapFunc, reduceFunc, { finalize: finalFunc, out: { inline: 1 }});