Im trying to search through a collection and group records by date field which is a datetime. I know pymongo converts those to the proper type on the background (ISODate or
Yes. You can use the Date Operators with $substr and $concat to tie it all together.
db.test.aggregate([
{"$group": {
"_id" : { "$concat": [
{"$substr": [{"$year": "$date"}, 0, 4 ]},
"-",
{"$substr": [{"$month": "$date"}, 0, 2 ]},
"-",
{"$substr": [{"$dayOfMonth": "$date"}, 0, 2 ]},
]},
"count": {"$sum": 1 }
}},
{"$sort": { "_id": 1 }}
])
You could use just the date operators and make a document as in:
"day": {
"year": {"$year": "$date" },
"month": {"$month": "$date"},
"day": {"$dayOfYear": "$date"}
}
That works just as well. But this gives you a nice string. This makes use of the fact that $substr
will cast from integer to string. If that ever gets added to the documentation.
Look at the Date Operators documentation for usage on the other time divisions that can be used on dates.
Better yet, use date math to return a BSON Date:
import datetime
db.test.aggregate([
{ "$group": {
"_id": {
"$add": [
{ "$subtract": [
{ "$subtract": [ "$date", datetime.datetime.utcfromtimestamp(0) ] },
{ "$mod": [
{ "$subtract": [ "$date", datetime.datetime.utcfromtimestamp(0) ] },
1000 * 60 * 60 * 24
]}
]},
datetime.datetime.utcfromtimestamp(0)
]
},
"count": { "$sum": 1 }
}},
{ "$sort": { "_id": 1 } }
])
Here datetime.datetime.utcfromtimestamp(0) will be fed into the pipeline as a BSON Date representing "epoch". When you $subtract one BSON Date from another the difference in milliseconds is returned. This allows you to "round" the date to the current day by again subtracting the $mod result to get the remainder of milliseconds difference from a day.
The same is true of $add where "adding" a BSON Date to a numeric value will result in a BSON Date.