Group通过在MongoDb上的聚合

问题描述:

我使用的是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)" 

您需要在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

要获得间隙间隔的结果,你可以使用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阶段。

你可以很容易地用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})