2016-01-22 51 views
5

我使用的是mongodb 2.6。我已經存儲在這個形式我的數據:Group通過在MongoDb上的聚合

{ 
    "_id" : "my-sensor-1", 
    "points": [ 
     { "timeStamp" : NumberLong("1453468362174"), "value" : 41 }, 
     { "timeStamp" : NumberLong("1453468483297"), "value" : 66 }, 
     { "timeStamp" : NumberLong("1453468485568"), "value" : 49 }, 
     ...  
    ] 
} 

爲了聚集我作出這樣的查詢文件:

db.pointsTest.aggregate([ 
    { $match: { $and: [ {"points.timeStamp" : { $gt : 1453433925163}}, 
         {"_id":"my-sensor-10"} ] } }, 
    {"$unwind":"$points"}, 
    {$group: {_id: "my-sensor-1","average":{$avg : "$points.value"}}} 
]) 

{ 「_id」:「我的傳感器-1 」, 「平均」:52}

結果

我將時間戳存儲爲毫秒,所以每次我想要聚合特定時間間隔時,我都必須更改timeStamp值的範圍。

我該如何在一段時間內進行聚合,並按間隔時間間隔對結果進行分組(即將從now()-1天的聚合平均值1h)?

編輯

我想讓這樣的事情:

db.pointsTest.aggregate([ 
    { $match: { $and: [ {"points.timeStamp" : { $gt : 1453433925163, $lt : 1453555555555}}, {"_id":"my-sensor-10"} ] } }, {"$unwind":"$points"}, {$group: {_id: "my-sensor-1","average":{$avg : "$points.value"}, ???}} 
]) 

,其結果將是1H分組在此時間間隔的平均值。 假設欲聚合的平均值爲十二月31的每隔一小時:

的間隔31/12/2015 20點00分00秒,平均時間戳:的間隔31的xyz

時間戳/二千零十五​​分之一十二21:00:00,平均:XYZ

此時爲了達到我要的時間間隔1小時間隔分割並進行多次數據庫請求。使用InfluxDB做我做同樣的

IE:

"SELECT MEAN(value) From myMeasures where key='my-sensor-1' and time > now() - 1d GROUP BY time(1h)" 

回答

1

您需要在Mongo查詢中進行一些數學計算,以便根據不同的時間間隔對數據進行分組。

$ subtract和$ mod的組合將幫助您按特定間隔對數據進行分組。

查詢會像下面:

db.sensor.aggregate({ 
    $match: { 
    $and: [{ 
     "points.timeStamp": { 
      $gt: 1453433925163, 
      $lt: 1453555555555 
     } 
    }, { 
     "_id": "my-sensor-1" 
    }] 
    } 
}, { 
    $unwind: "$points" 
}, { 
    "$group": { 
    "_id": { 
     "$subtract": ["$points.timeStamp", { 
      "$mod": ["$points.timeStamp", 1000 * 60] 
     }] 
    }, 
    "average": { 
     "$avg": "$points.value" 
    } 
    } 
}) 

希望,這將有利於你。

+0

真正有用的,但我認爲這是失去了一些東西(也許我沒有具體說明它在我的問題)。爲了迭代列表中的項目,我必須添加另一個$匹配項,因爲當條件爲真時,它會返回整個項目。所以查詢是這樣的: db.pointsTest.aggregate({$ match:{$ and:[{「points.timeStamp」:{$ gte:1453797806927}},{「_id」:「my-sensor-1」} ]},{$ unwind:「$ points」},{$ match:{「points.timeStamp」:{$ gte:1453797806927}}},{「$ group」:{「_id」:{「$ subtract」 :[「$ points.timeStamp」,{「$ mod」:[「$ points.timeStamp」,1000 * 60]}]},「average」:{「$ avg」:「$ points.value」}}} ) – bill

1

要獲得間隙間隔的結果,你可以使用JavaScript函數來支持你的查詢,因爲MongoDB的shell支持他們:

執行與示例中的例子,你提供的,要$match值從now()-1day,您可以在聚合之前:

​​

yesterday.getTime()將產生日期milis,您可以在$match階段

db.pointsTest.aggregate([ 
    { $match: { $and: [ {"points.timeStamp" : { $gt : yesterday.getTime()}}, 
         {"_id":"my-sensor-10"} ] } }, 

我們在每小時一班分組結果用它在你的聚集,我會在$group前添加$project階段,加一個新的字段,其中小時間隔計算,points.timeStamp - yesterday.getTime()你會得到初始時間和輸入時間之間的總差異毫秒數,你將其轉換爲小時,然後取整到下一個整數值。

最後,使用$project階段中的新字段用於$group階段。

1

你可以很容易地用mongodb mapReduce做到這一點。

試試下面的代碼:

// generate a query to filter result by date and _id. 
// be aware that our query matches documents that contain an array field with 
// at least one element that matches all the specified criteria. 
var yesterday = new Date(); 
yesterday.setDate(yesterday.getDate()-1); 
var query = {"points.timeStamp" : { $gt : yesterday.getTime()}, "_id":"my-sensor-1"}; 

var map = function(){ 
    var points = this.points; 
    for(var i=0;i<points.length;i++){ 
     var date = new Date(points[i].timeStamp); 

     //remove minutes, seconds and milliseconds from the date and emit it 
     date.setHours(date.getHours(), 0, 0, 0); 
     emit(date, points[i].value); 
    } 
}; 

var reduce = function(key, values){ 
    //calculate average 
    var total = 0; 
    for(var i = 0; i < values.length; i++) { 
     total += values[i]; 
    } 
    var avg = total/values.length; 
    return avg; 
}; 

db.pointsTest.mapReduce(map, reduce, {out:{inline: 1}, query: query})