我有这样的文档:
{
"_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")
}
}
我想按"名称"、"动作"one_answers"日期"对地图简化文档进行分组。但是每个文档都应该有这个"firstEncounteredDate",它包含最早的"日期"(实际上是按"名称"one_answers"动作"分组的)。
如果我按名称,操作和日期分组,firststencountereddate将始终是日期,这就是为什么我想知道是否有任何方法在执行map-reduce时获得"最早日期"(按"名称"one_answers"操作"分组)。
如何在mapreduce中做到这一点?
编辑:更多关于firstEncounteredDate的细节(来自@beny23)
似乎两次map-reduce符合要求,有点类似于这个例子:http://cookbook.mongodb.org/patterns/unique_items_map_reduce/
在步骤#1中,将原始的"name"x"action"x"date"文档仅按"name"one_answers"action"分组,在reduce期间将各种"date"值收集到"dates"数组中。使用'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中生成的文档作为输入。对于每个"name"x"action"文档,为每个收集到的日期生成一个新的"name"x"action"x"date"文档,以及现在确定的"name"x"action"对共有的最小日期。按"名称"x"动作"x"日期"分组,汇总reduce过程中每个单独日期的计数。
同样未经测试的代码:
// 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次,每个唯一日期一次。我们可以很容易地在pass #1的减少步骤中建立一个独特日期的发生率计数图。(事实上,如果我们不这样做,那么在传递#1的值中使用"count"字段就没有真正的意义了。)但是执行第二遍是一种相当轻松的方法,可以生成包含所需文档的完整目标集合。