2014-10-29 102 views
0

我有这个聚合管道代码下面,我想运行一年中的每一天!基本上计算一年中每一天的最低,最高和平均温度(“TEMP”字段)。目前我正在调用这段代码365次,通过一天的开始日期和结束日期。MongoDB聚合管道与循环

显然这是非常低效的。有没有什么办法可以在mongo中循环,以便更快,并返回365个平均值,365分钟值和365个最大值或类似的数组。我使用时区库来派生开始日期和结束日期。

collection.aggregate([ 
    { 
    $match:{$and:[ 
     {"UID" : uid}, 
     {"TEMP" :{$exists:true}} 
     {"site" : "SITE123"}, 
     {"updatedAt": {$gte : new Date(START_DATE_ARG), $lte : new Date(END_DATE_ARG)} } 
     ]} 
    }, 

    { "$group": { 
     "_id": "$UID", 
     "avg": { $avg: $TEMP }, 
     "min": { $min: $TEMP }, 
     "max": { $max: $TEMP } 
     } 
    } 
], function(err, result){ 
       if (err){ 
        cb(1, err); 
       } 
       else{ 
        cb(0, result); 
       } 
      }); 
}); 

的数据集是这样的

.... 
{UID: "123", TEMP: 11, site: "SITE123", updatedAt: ISODate("2014-09-12T21:55:19.326Z")} 
{UID: "123", TEMP: 10, site: "SITE123", updatedAt: ISODate("2014-09-12T21:55:20.491Z")} 
.... 

任何想法?也许我们可以在聚合管道中传递一年中所有日子的所有时间戳?

谢谢!

回答

0

为什么每天都会运行这个操作,只需将分组键的日期部分?这就是date aggregation operators的存在,所以你可以通过时间框架在整个时期在一次无循环汇总:

collection.aggregate([ 
    { "$match":{ 
     "UID": uid, 
     "TEMP":{ "$exists": true } 
     "site" : "SITE123", 
     "updatedAt": { 
      "$gte": new Date(START_DATE_ARG), 
      "$lte": new Date(END_DATE_ARG) 
     }} 
    }}, 

    { "$group": { 
     "_id": { 
      "uid": "$UID", 
      "year": { "$year": "$updatedAt" }, 
      "month": { "$month": "$updatedAt" }, 
      "day": { "$dayOfMonth" } 
     }, 
     "avg": { "$avg": "$TEMP" }, 
     "min": { "$min": "$TEMP" }, 
     "max": { "$max": "$TEMP" } 
    }} 
]) 

也可能只冷凝日期时间戳值来代替。日期数学的一个小技巧与Date对象:

collection.aggregate([ 
    { "$match":{ 
     "UID": uid, 
     "TEMP":{ "$exists": true } 
     "site" : "SITE123", 
     "updatedAt": { 
      "$gte": new Date(START_DATE_ARG), 
      "$lte": new Date(END_DATE_ARG) 
     }} 
    }}, 

    { "$group": { 
     "_id": { 
      "uid": "$UID", 
      "date": { 
       "$subtract": [ 
        { "$subtract": [ "$updatedAt", new Date("1970-01-01") ] }, 
        { "$mod": [ 
         { "$subtract": [ "$updatedAt", new Date("1970-01-01") ] }, 
         1000 * 60 * 60 * 24 
        ]} 
       ] 
      } 
     }, 
     "avg": { "$avg": "$TEMP" }, 
     "min": { "$min": "$TEMP" }, 
     "max": { "$max": "$TEMP" } 
    }} 
]) 

当然你的“日期范围”这里现在是您需要是在结果的日期的所有,所以一开始和所有的结束日期你打算循环的东西。分组在两种情况下完成以反映“有一天”,但当然您可以将其更改为您想要的任何间隔。

另请注意,您在这里使用$and是没有必要的。 MongoDB中的查询“和”默认条件“。唯一需要该运算符的时间是在同一个字段中的多个条件,否则这些条件将不是有效的JSON/BSON。

+0

嗨尼尔,谢谢!关于时区会发生什么?如果我使用内置$ dayOfMonth,$ week运算符,是否有调整时区的最佳做法? – opcode 2014-10-29 18:35:15

+0

确实时区功能尚未实现。跟踪:https://jira.mongodb.org/browse/SERVER-6310 我猜即使增加一个偏移量的查询将不会有太大的帮助,由于夏令时等。 – opcode 2014-10-30 01:32:44