MongoDB 聚合今天的记录
我正在使用MongoDB的聚合框架来处理一组记录。
相关的代码片段是:
Record._get_collection().aggregate([
{ "$match": {
"system_id": system.id
}},
...
我该如何修改这个代码,以便只聚合今天的记录呢?
一个Record
文档里有一个utc_timestamp
字段,所以我觉得应该像这样:
Record._get_collection().aggregate([
{ "$match": {
"system_id": system.id,
{ "$dayOfMonth": "$utc_timestamp" }: 5
}},
...
这样做对吗?
1 个回答
为了获取当前日期的记录,你基本上需要提供一个日期范围,这个范围代表了当天的开始和结束时间。假设你在你的类中使用了一个叫做DateTimeField的字段,那么MongoDB会使用一种叫做BSON日期的类型,这种类型可以和日期聚合操作一起使用。
Record._get_collection().Aggregate([
{ "$match": {
"system_id": system.id,
"utc_timestamp": {
"$gte": datetime.datetime(2014,9,6)
"$lt": datetime.datetime(2014,9,7)
}
}},
{ "$group": {
"_id": { "$dayOfYear": "$utc_timestamp" }
....
在$group
操作中,这些操作通常在聚合超过一天的值时最有意义,或者在一天内按小时或分钟聚合。否则,由于日期已经被选定,那么所有的记录都是当前日期,任何其他字段的聚合键或者Null
值基本上都是在为那一天进行聚合。
如果你所说的“时间戳”实际上是一个表示自纪元以来的秒数的数字(BSON类型内部实际上使用的是自纪元以来的毫秒数),那么你可以这样构建你的查询:
Record._get_collection().Aggregate([
{ "$match": {
"system_id": system.id,
"utc_timestamp": {
"$gte": ( datetime.datetime(2014,9,6)
- datetime.datetime(1970,1,1)).total_seconds()
"$lt": ( datetime.datetime(2014,9,7)
- datetime.datetime(1970,1,1)).total_seconds()
}
}},
{ "$group": {
"_id": {
"$subtract": [
"$utc_timestamp",
{ "$mod": [
"$utc_timestamp",
60 * 60 * 24
]}
]
},
...
或者类似地,如果你想调整为毫秒,这是更常见的纪元时间戳格式,可以通过乘以1000来实现。对于分组,标准的“日期计算”适用,通过将匹配的时间戳值四舍五入到当前日期。
最后,MongoEngine支持一种叫做ComplexDateTimeField的字段,它可以保留在Python datetime对象中通常可用的微秒。不过有一点不太好的是,在MongoDB中实际存储的是一个“字符串”,所以在数学计算或一般日期操作上并不太好用。但这个字符串的格式是YYYY,MM,DD,HH,MM,SS,NNNNNN
,至少在“字典”排序上是有序的,因此可以通过$substr
进行范围选择和拆分,以便聚合到某一天或其他时间段:
Record._get_collection().Aggregate([
{ "$match": {
"system_id": system.id,
"utc_timestamp": {
"$gte": "2014,09,06", "$lt": "2014,09,07"
}
}},
{ "$group": {
"_id": { "$substr": [ "$utc_timestamp", 0, 10 ] }
...
但是如果你使用的是其他形式的字符串,那么你可能会遇到问题,因为它可能无法很好地转换用于查询匹配或分组键选择。在这种情况下,最好将这些字符串转换为上述的某种形式,显然优先使用原生的BSON日期类型,因为这是支持最好的形式。