Sie können tatsächlich ein beliebiges Objekt an den zweiten Parameter des Emit-Aufrufs übergeben. Das heißt, Sie können dies ausnutzen und die Benutzer-ID darin speichern. Ihre Kartenfunktion kann beispielsweise so aussehen:
var mapFunc = function() {
if (this.track_redirect) {
var tempDoc = {};
tempDoc[this.track_userid] = 1;
emit(this.track_redirect, {
users_clicked: tempDoc,
total_clicks: 1
});
}
};
Und Ihre Reduce-Funktion könnte so aussehen:
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;
};
Die Eigenschaft users_clicked des Zusammenfassungsobjekts speichert grundsätzlich die ID jedes Benutzers als Eigenschaft (da Sie keine doppelten Eigenschaften haben können, können Sie garantieren, dass eindeutige Benutzer gespeichert werden). Beachten Sie auch, dass Sie darauf achten müssen, dass einige der an die Reduce-Funktion übergebenen Werte das Ergebnis einer vorherigen Reduce-Funktion sein können und der obige Beispielcode dies berücksichtigt. Weitere Informationen zu diesem Verhalten finden Sie in der Dokumentation hier .
Um die eindeutige Anzahl zu erhalten, können Sie die Finalizer-Funktion übergeben, die aufgerufen wird, wenn die Reduzierungsphase abgeschlossen ist:
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)
};
};
Schließlich können Sie den Map-Reduce-Job wie folgt ausführen (ändern Sie das out-Attribut, um es Ihren Anforderungen anzupassen):
db.users.mapReduce(mapFunc, reduceFunc, { finalize: finalFunc, out: { inline: 1 }});