2014-10-29 131 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