Count of Events within a MongoDB Collection by Day within a Date Range
-
21-12-2019 - |
Question
I am trying to figure out how to perform a count of events within a MongoDB collection, by all dates occurring within a specified date range.
Sample Document Schema within MongoDB:
{
eventNum: 1234,
startDate:ISODate("2014-01-01"),
endDate: ISODate("2014-01-04")
eventType: System Crash
}
{
eventNum: 4567,
startDate: ISODate("2014-01-04"),
endDate: ISODate("2014-01-05")
eventType: Maintenance
}
What I am trying to get at is for the Date Range:
1/1/2014 - 1/6/2014
What is the total count events for each day within this range?
Results would be:
1/1/2014: 1
1/2/2014: 1
1/3/2014: 1
1/4/2014: 2
1/5/2014: 1
1/6/2014: 0
My problem really lies in the fact that the data being tracked is not on an individual day basis, which would have allowed me to perform a basic aggregation by Date. The events have a start and end date.
Solution
More of a mapReduce problem unfortunately as you would otherwise not be able to emit the dates required to make this work.
db.events.mapReduce(
function() {
var oneDay = ( 1000 * 60 * 60 * 24 ),
start = this.startDate.valueOf()
- ( this.startDate.valueOf() % oneDay ),
end = ((this.endDate.valueOf()
- ( this.endDate.valueOf() % oneDay )) + oneDay);
for ( var day = start; day < end; day += oneDay ) {
emit ( new Date( day ), 1 );
}
},
function(key, values) {
return Array.sum( values );
},
{
"query": {
"startDate": { "$gte": new Date("2014-01-01") },
"endDate": { "$lt": new Date("2014-01-06") }
},
"out": { "inline": 1 }
}
)
If you really want the zero values for events that do not exist within the date range you can alter a little:
db.events.mapReduce(
function() {
var oneDay = ( 1000 * 60 * 60 * 24 ),
start = this.startDate.valueOf()
- ( this.startDate.valueOf() % oneDay ),
end = ((this.endDate.valueOf()
- ( this.endDate.valueOf() % oneDay )) + oneDay);
for ( var day = start; day < end; day += oneDay ) {
emit ( new Date( day ), 1 );
}
for ( var day = end; day <= ending.valueOf(); day += oneDay ) {
emit( new Date( day ), 0 );
}
},
function(key, values) {
return Array.sum( values );
},
{
"query": {
"startDate": { "$gte": new Date("2014-01-01") },
"endDate": { "$lt": new Date("2014-01-06") }
},
"scope": { "ending": new Date("2014-01-06") },
"out": { "inline": 1 }
}
)
Which gives you the output you want:
"results" : [
{
"_id" : ISODate("2014-01-01T00:00:00Z"),
"value" : 1
},
{
"_id" : ISODate("2014-01-02T00:00:00Z"),
"value" : 1
},
{
"_id" : ISODate("2014-01-03T00:00:00Z"),
"value" : 1
},
{
"_id" : ISODate("2014-01-04T00:00:00Z"),
"value" : 2
},
{
"_id" : ISODate("2014-01-05T00:00:00Z"),
"value" : 1
},
{
"_id" : ISODate("2014-01-06T00:00:00Z"),
"value" : 0
}
]