使用having子句和where条件映射减少组的代码

时间:2012-08-23 10:57:42

标签: php mongodb map reduce

我有一个用户集合如下

{
    "id":"id here", 
    name: 'name here', 
    height: 'height here', 
    weight: 'weight here', 
    lastLogin:[array of login dates], 
    messagesSentOn: [array of messages sent date]
}

我需要查找上个月登录但不止一次且上个月发送的邮件超过25条且权重超过50且高度超过5英寸的所有用户。对于上述情况,如何在mongodb中编写map reduce函数?

1 个答案:

答案 0 :(得分:1)

我在shell中提供了一个示例。我不确定MR是否是解决此问题的最佳解决方案,我建议您考虑使用其他解决方案以避免使用单线程Javascript。例如,您可以存储仅包含当前月份的登录或消息的其他字段。每次添加登录名和/或消息时,都会增加计数器字段。此模式允许您在没有聚合命令的情况下查找匹配的文档。

您还应该查看新的聚合框架,该框架将在MongoDB 2.2版中提供(即将发布):http://docs.mongodb.org/manual/applications/aggregation/

最后一点 - 为了提高性能,您应该确保在MR命令中包含一个查询以清除不匹配的文档(参见下面的示例)。

输入文件:

{ "_id" : 1, "name" : "Jenna", "height" : 100, "weight" : 51, "lastLogin" : [ 1, 2, 3, 4 ], "messageSentOn" : [ 4, 5, 5, 7 ] }
{ "_id" : 2, "name" : "Jim", "height" : 60, "weight" : 49, "lastLogin" : [ 2, 4 ], "messageSentOn" : [ 5, 6 ] }
{ "_id" : 3, "name" : "Jane", "height" : 90, "weight" : 60, "lastLogin" : [ 1 ], "messageSentOn" : [ 3, 6 ] }
{ "_id" : 4, "name" : "Joe", "height" : 70, "weight" : 65, "lastLogin" : [ 5, 6, 7 ], "messageSentOn" : [ 3, 6, 7 ] }

MR功能:

map = function(){ 
   var monthLogins = 0; 
   var monthMessages = 0; 
   var monthDate = 2;  
   for(var i=0; i<this.lastLogin.length; i++){     
       if(this.lastLogin[i] > monthDate){         
            monthLogins++; 
       } 
   } 
   for(var i=0; i<this.messageSentOn.length; i++){     
      if(this.messageSentOn[i] > monthDate){         
         monthMessages++; 
      } 
   } 
   if(monthLogins > 1 && monthMessages > 2)
      { emit(this._id, null); 
   } 
}

reduce = function (key, values) {
   //won't be called because a single document is emitted for each key
}

MR命令:

db.collection.mapReduce(map, reduce, {query: {weight: {$gt : 50}, height: {$gt: 5}, lastLogin: {$gt: 2}}, out: {inline:1}})

输出:

{"_id" : 1, "value" : null},
{"_id" : 4, "value" : null}