MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

come calcolare il conteggio e il conteggio univoco su due campi nella funzione di riduzione mongo

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 }});