MongoDB 聚合今天的记录

1 投票
1 回答
1603 浏览
提问于 2025-04-20 01:55

我正在使用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 个回答

2

为了获取当前日期的记录,你基本上需要提供一个日期范围,这个范围代表了当天的开始和结束时间。假设你在你的类中使用了一个叫做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日期类型,因为这是支持最好的形式。

撰写回答