Mongodb 如何在mongo reduce函数中计算两个字段的计数和唯一计数

Mongodb 如何在mongo reduce函数中计算两个字段的计数和唯一计数,mongodb,mapreduce,Mongodb,Mapreduce,我有一个链接跟踪表,其中包含(除其他字段外)track_redirect和track_userid。我想输出一个给定链接的总计数,以及按用户id重复计数的唯一计数。因此,我们可以区分是否有人单击了同一链接5次 我尝试在key和values部分发出this.track_userid,但无法掌握如何在reduce函数中正确访问它们 因此,如果我回到它实际工作的时间,我有下面非常简单的代码——就像“我的第一个mapreduce函数”示例中的代码一样 地图 减少 function(k, vals) {

我有一个链接跟踪表,其中包含(除其他字段外)track_redirect和track_userid。我想输出一个给定链接的总计数,以及按用户id重复计数的唯一计数。因此,我们可以区分是否有人单击了同一链接5次

我尝试在key和values部分发出this.track_userid,但无法掌握如何在reduce函数中正确访问它们

因此,如果我回到它实际工作的时间,我有下面非常简单的代码——就像“我的第一个mapreduce函数”示例中的代码一样

地图

减少

function(k, vals) {
  var sum = 0;
  for (var i in vals) {
    sum += vals[i];
  } 
  return sum;
}
我想知道发出附加用户ID信息并在mapreduce中访问它的正确方法。还是我想的不对

如果不清楚,我不想计算一个用户ID的总点击量,但要计算每个url+用户ID的唯一点击量-不计算用户ID在每个链接上的任何重复点击量


有人能给我指一下正确的方向吗?谢谢

您实际上可以在emit调用的第二个参数上传递任意对象。这意味着您可以利用它并在其中存储用户ID。例如,映射函数可以如下所示:

var mapFunc = function() {
  if (this.track_redirect) {
    var tempDoc = {};
    tempDoc[this.track_userid] = 1;

    emit(this.track_redirect, {
      users_clicked: tempDoc,
      total_clicks: 1
    });
  }
};
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;
};
您的reduce函数可能如下所示:

var mapFunc = function() {
  if (this.track_redirect) {
    var tempDoc = {};
    tempDoc[this.track_userid] = 1;

    emit(this.track_redirect, {
      users_clicked: tempDoc,
      total_clicks: 1
    });
  }
};
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;
};
summary对象的users\u clicked属性基本上将每个用户的id存储为一个属性(因为您不能有重复的属性,所以可以保证它将存储唯一的用户)。还请注意,您必须注意,传递给reduce函数的某些值可能是先前reduce的结果,上面的示例代码考虑了这一点。您可以在文档中找到有关上述行为的更多信息

为了获得唯一计数,您可以传入在reduce阶段完成时调用的finalizer函数:

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)
  };
};
最后,您可以像这样执行map reduce作业(修改out属性以满足您的需要):


谢谢你,任,这是完全正确的。对于这个例子来说,使用我现在的数据是很好的,因为我现在已经理解了!很好的第一个回答,伙计!如果有人偶然发现了这条线索,这可能会很有用:我已经写了任的答案,包括显示每个阶段之间的数据