2011-09-19 34 views
1

我有这样的文件:mongodb地图缩小:“第一/最低”值?

{ 
     "_id" : "someid", 
     "name" : "somename", 
     "action" : "do something", 
     "date" : ISODate("2011-08-19T09:00:00Z") 
} 

我要地图降低他们弄成这个样子:

{ 
     "_id" : "someid", 
     "value" : { 
      "count" : 100, 
      "name" : "somename", 
      "action" : "do something", 
      "date" : ISODate("2011-08-19T09:00:00Z") 
      "firstEncounteredDate" : ISODate("2011-07-01T08:00:00Z") 
     } 
} 

我想组地图减少了“名”,“行动”的文件,和“日期”。但是每个文档应该包含最早的“日期”(实际上由“名称”和“动作”分组)的这个“firstEncounteredDate”。

如果按名称,操作和日期进行分组,firstEncounteredDate将始终为日期,这就是为什么我想知道是否有任何方法获得“最早日期”(按“name”和“action”分组)从整个文档),而做map-reduce。

我该如何在地图缩小中做到这一点?

编辑:上firstEncounteredDate更详细(礼貌@ beny23)

+0

你能说清楚firstEncounteredDate是如何计算的吗?因为如果你通过'name','action'和'date'进行分组,不会'firstEncounteredDate'总是'date'? – beny23

+0

firstEncounteredDate应该是最早的日期(即在整个文档中有所不同)。如果按名称,操作和日期分组,firstEncounteredDate总是日期,这就是为什么我想知道是否有任何方法可以从整个文档中获得“最早日期”(按“name”和“action”分组同时做map-reduce。 – EwyynTomato

回答

2

似乎是一个两通地图,减少将适合的纸币,有点类似于该实施例中:http://cookbook.mongodb.org/patterns/unique_items_map_reduce/

在通#1,通过“名称”和“操作”将原始“名称”x“操作”x“日期”文档分组,在缩减过程中将各种“日期”值收集到“日期”数组中。使用'finalize'函数来查找收集日期的最小值。

未经测试的代码:

// phase i map function : 

function() { 
    emit({ "name": this.name, "action": this.action } , 
     { "count": 1, "dates": [ this.date ] }); 
} 

// phase i reduce function : 

function(key, values) { 
    var result = { count: 0, dates: [ ] }; 

    values.forEach(function(value) { 
    result.count += value.count; 
    result.dates = result.dates.concat(value.dates); 
    } 

    return result; 
} 

// phase i finalize function : 

function(key, reduced_value) { 
    var earliest = new Date(Math.min.apply(Math, reduced_value.dates)); 
    reduced_value.firstEncounteredDate = earliest ; 
    return reduced_value; 
} 

在通#2时,使用在通#1中生成作为输入的文件。对于每个“名称”x“动作”文档,为每个收集日期发出一个新的“名称”x“动作”x“日期”文档,以及现在确定的该“名称”x“动作”对共同的最短日期。按“名称”x“操作”x“日期”进行分组,总结减少期间每个单独日期的计数。

同样未经测试的代码:

// phase ii map function : 

function() { 
    this.dates.forEach(function(d) { 
    emit({ "name": this.name, "action": this.action, "date" : d } , 
      { "count": 1, "firstEncounteredDate" : this.firstEncounteredDate }); 
    } 
} 

// phase ii reduce function : 

function(key, values) { 
    // note: value[i].firstEncounteredDate should all be identical, so ... 
    var result = { "count": 0, 
       "firstEncounteredDate": values[0].firstEncounteredDate }; 

    values.forEach(function(value) { 
    result.count += value.count; 
    } 

    return result; 
} 

通#2没有做很多繁重的工作,很明显 - 它主要是复制的每个文档N次,每一个独特的日期。在通过#1的减少步骤期间,我们可以轻松地为他们的发病次数建立独特日期的地图。 (实际上,如果我们不需要这样做,那么在传递#1的值中有一个“count”字段没有实际意义。)但是,执行第二遍是生成完整目标集合的一种相当轻松的方式包含所需的文件。