MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

como calcular a contagem e a contagem única em dois campos na função de redução do mongo


Você pode realmente passar um objeto arbitrário no segundo parâmetro da chamada de emissão. Isso significa que você pode aproveitar isso e armazenar o ID do usuário nele. Por exemplo, sua função de mapa pode ser assim:
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 sua função de redução pode ficar assim:
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;
};

A propriedade users_clicked do objeto de resumo basicamente armazena o id de cada usuário como uma propriedade (já que você não pode ter propriedades duplicadas, você pode garantir que ele armazenará usuários únicos). Observe também que você deve ter cuidado com o fato de que alguns dos valores passados ​​para a função de redução podem ser resultado de uma redução anterior e o código de exemplo acima leva isso em consideração. Você pode encontrar mais sobre o referido comportamento nos documentos aqui .

Para obter a contagem exclusiva, você pode passar a função finalizadora que é chamada quando a fase de redução é concluída:
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)
  };
};

Por fim, você pode executar o trabalho de redução do mapa assim (modifique o atributo out para atender às suas necessidades):
db.users.mapReduce(mapFunc, reduceFunc, { finalize: finalFunc, out: { inline: 1 }});