I am using Mongo's mapReduce function to aggregate meter generation
data for a specific home within a specified date range. The problem
is that I cannot get Mongo to query the date ranges based on UTC, it
always seems to be apply my local timezone offset (EST -5 hours) to
the range no matter what I do.
Here is my raw data in Mongo:
{ "_id" : NumberLong(180240), "className" :
"models.generation.MeterMessage", "gin" : "1.1", "sn" : "567890",
"at" : ISODate("2011-03-01T00:00:00Z"), "gen" : 10,
"aggregationStatus" : false }
{ "_id" : NumberLong(180241), "className" :
"models.generation.MeterMessage", "gin" : "1.1", "sn" : "567890",
"at" : ISODate("2011-03-01T01:00:00Z"), "gen" : 10,
"aggregationStatus" : false }
{ "_id" : NumberLong(180242), "className" :
"models.generation.MeterMessage", "gin" : "1.1", "sn" : "567890",
"at" : ISODate("2011-03-01T02:00:00Z"), "gen" : 5,
"aggregationStatus" : false }
{ "_id" : NumberLong(180243), "className" :
"models.generation.MeterMessage", "gin" : "1.1", "sn" : "567890",
"at" : ISODate("2011-03-02T01:00:00Z"), "gen" : 20,
"aggregationStatus" : true }
{ "_id" : NumberLong(180244), "className" :
"models.generation.MeterMessage", "gin" : "1.1", "sn" : "567890",
"at" : ISODate("2011-03-02T02:00:00Z"), "gen" : 20,
"aggregationStatus" : true }
{ "_id" : NumberLong(180245), "className" :
"models.generation.MeterMessage", "gin" : "1.1", "sn" : "567890",
"at" : ISODate("2011-03-03T00:00:39Z"), "gen" : 20,
"aggregationStatus" : true }
I am using JUnit for testing, and this is how I am passing in my date
range to the aggregator (using Joda DateTime).
final Interval range = new Interval(new
DateTime(2011,3,1,0,0,0,0), new DateTime(2011,3,2,23,59,59,999));
In my aggregation method I use a BasicDBObject to build part of my
query:
BasicDBObject obj = new BasicDBObject("$gte",
dateRange.getStart().toDate()).append("$lt",
dateRange.getEnd().toDate());
The resulting query used by the map reduce function is:
{ "gin" : "1.1" , "at" : { "$gte" : { "$date" :
"2011-03-01T05:00:00.000Z"} , "$lt" : { "$date" :
"2011-03-03T04:59:59.999Z"}}}
Here are my map / reduce functions and the call I make the Mongo to
perform the map reduce
final String dailyGenerationMapFunction =
"function() { " +
" emit (" +
" this.at.getFullYear() + '-' + (this.at.getMonth()+1) + '-'
+ this.at.getDate(), " +
" { at:
this.at, gen: this.gen }); " +
"}";
final String sumGenerationReduceFunction =
"function(v, vals) {" +
" var sum = 0; " +
" for(var i in vals) {" +
" sum += vals[i].gen;" +
" }" +
" return { at: v, gen: sum };"+
"}";
I call Mongo's mapReduce function like so (I doubt it matters but my
collection is obtained through Morphia):
DBCollection dbCol =
MorphiaPlugin.ds().getCollection(MeterMessage.class)
dbCol. mapReduce(mapFunction, reduceFunction, "GenerationOutput",
query)
After I run the function my resulting output is not really what I
expect it to be. It "inaccurately" bundled the generation data from
3-1 into 2-28.. hmm..
{ "_id" : "2011-2-28", "value" : { "at" : "2011-2-28" , "gen" :
25.0}}
{ "_id" : "2011-3-1", "value" : { "at" : "2011-3-1" , "gen" :
40.0}}
{ "_id" : "2011-3-2", "value" : { "at" : { "$date" :
"2011-03-03T00:00:39.000Z"} , "gen" : 20.0}}
In an attempt to fix this I tried forcing the initial date range from
JUnit to be in UTC like so:
final Interval range = new Interval(new
DateTime(2011,3,1,0,0,0,0).withZone(DateTimeZone.UTC), new
DateTime(2011,3,2,23,59,59,999).withZone(DateTimeZone.UTC));
Cool, so now the map reduce function is in plain UTC and doesn't
consider my local timezone offset:
{ "gin" : "1.1" , "at" : { "$gte" : { "$date" :
"2011-03-01T00:00:00.000Z"} , "$lt" : { "$date" :
"2011-03-03T23:59:59.999Z"}}}
However, the resulting aggregated data remains unchanged...:
{ "_id" : "2011-2-28" , "value" : { "at" : "2011-2-28" , "gen" :
25.0}}
{ "_id" : "2011-3-1" , "value" : { "at" : "2011-3-1" , "gen" :
40.0}}
{ "_id" : "2011-3-2" , "value" : { "at" : { "$date" :
"2011-03-03T00:00:39.000Z"} , "gen" : 20.0}}
I have been struggling heavily with these date range queries and am
pretty much running out of things to try. Why is it that no matter
what I do Mongo always just uses my local timezone when looking at the
data?
Thanks
Erik