Question

My collection has documents like this:

day

--hour

----minute

...where each hour is a property on day, and each minute is a property on an hour:

///first hour, first minute ... last hour, last minute
{
 0: {0:{x:1, y:2}...59:{x:3, y:8}}
 ...
 23: {0:{x:1, y:2}...59:{x:3, y:8}} 
}

I want to average the values on the properties of the minutes to return a collection of documents like this:

//first hour, average values ... last hour, average values

{
0:{x:2, y:5}
...
23:{x:2, y:5}
}

Can I use mapReduce or the aggregation pipeline to do this? How?

One hitch: I also want to filter out preformatted minutes like this:

59: {x:0, y:0} // zero means null record 
Was it helpful?

Solution

Yes this is straight out mapReduce logic without a reducer.

So considering you have structure somewhat like this:

{
    "series": {
        0:  { 0:{x:1, y:2}, 1: { x:0, y:0 }, 59:{x:3, y:8} },
        23: { 0:{x:1, y:2}, 59:{x:3, y:8} } 
    }
}

Then you define a mapper:

var mapper = function () {

  var output = {};

  for ( h in this.series ) {

    var minutes = {x: 0, y: 0};
    var count = 0;

    for ( m in this.series[h] ) {
      if ( ( this.series[h][m].x != 0 ) &&
           ( this.series[h][m].y != 0 ) )
      {
        minutes.x += this.series[h][m].x;
        minutes.y += this.series[h][m].y;
        count++;
      }
    }

    minutes.x = Math.floor( minutes.x / count );
    minutes.y = Math.floor( minutes.y / count );

    output[h] = minutes;

  }

  emit( this._id, output );

};

And then run the mapReduce:

db.series.mapReduce(mapper,function(){},{ out: { inline: 1 } })

Which gives you the output:

    "results" : [
            {
                    "_id" : ObjectId("53618345e10ce3c73df3ff24"),
                    "value" : {
                            "0" : {
                                    "x" : 2,
                                    "y" : 5
                            },
                            "23" : {
                                    "x" : 2,
                                    "y" : 5
                            }
                    }
            }
    ],

And will do so for each document.

With your current structure, transformation with the aggregation framework is not possible as all elements are sub-documents and cannot be traversed by the aggregation framework without explicitly naming each element

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top