我使用的是mongodb 2.6。我以这种形式存储了我的数据:
{
"_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" :" my-sensor-1","平均" :52}
结果
我已将时间戳存储为毫秒,因此每次我想要聚合特定时间间隔时,我必须更改timeStamp值的界限。
我怎样才能在一个时间段内进行聚合,并按间隙间隔对结果进行分组(即将现在的平均值()-1day GROUP乘以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分组。 假设我想要汇总12月31日每小时的平均值:
时间间隔31/12/2015 20:00:00,平均值:xyz
时间间隔31/12/2015 21:00:00,平均值:xyz
此时为了实现这一点,我必须以1小时的间隔分割时间间隔并向数据库发出多个请求。
I.E使用InfluxDB做同样的事情我这样做:
"SELECT MEAN(value) From myMeasures where key='my-sensor-1' and time > now() - 1d GROUP BY time(1h)"
答案 0 :(得分:2)
您需要在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"
}
}
})
希望,这对你有所帮助。
答案 1 :(得分:1)
要在间隙间隔中获得结果,您可以使用javascript函数来支持您的查询,因为mongodb shell支持它们:
要使用您提供的示例执行示例,您希望从$match
获得now()-1day
值,您可以在汇总之前执行此操作:
var now = new Date();
var yesterday = new Date();
// using getHours and setHours, since the Date object doesnt have method for getDays and setDays
yesterday.setHours(now.getHours() - 24);
yesterday.getTime()
将以milis格式生成日期,您可以在$match
阶段的汇总中使用该日期
db.pointsTest.aggregate([
{ $match: { $and: [ {"points.timeStamp" : { $gt : yesterday.getTime()}},
{"_id":"my-sensor-10"} ] } },
现在,要按小时间隔对结果进行分组,我会在$project
之前添加$group
阶段,以添加一个新字段,其中计算每小时间隔,{{1}你将获得初始时间和输入时间之间的总差异毫秒数,然后将其转换为小时数并向上舍入到下一个整数值。
最后,使用points.timeStamp - yesterday.getTime()
阶段的新字段,用于$project
阶段。
答案 2 :(得分: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})