我目前被困在这个上面。我有这样的收藏:
{
"_id": ObjectId("55820292e3dc84aa0c9c63bc"),
"creation_at": ISODate("2015-06-17T23:28:18.896Z"),
"cpu": 36,
"mem": "1.08"
}
并每 30 秒放入一些日志。我想按时间段获取摘要信息,例如:
[
{
'interval': ['2015-06-07 13:00:00', '2015-06-07 13:59:59'],
'cpu': {
'max': 20,
'min': 1,
'avg': 3
},
'memory': {
'max': 40,
'min': 35,
'avg': 38
}
},
{
'interval': ['2015-06-07 14:00:00', '2015-06-07 14:59:59'],
'cpu': { ... },
'memory': { ... }
},
...
...
...
]
从 mongo 文档中,我发现这可以通过聚合框架来实现,但我坚持生成时间间隔。你能给我指教吗?
内存在数据中显示为"字符串",因此除非您转换它,否则这将是一个问题。使用数值,对于具有日期聚合运算符的聚合框架来说,这很容易:
db.collection.aggregate([
{ "$group": {
"_id": {
"year": { "$year": "$creation_at" },
"month": { "$month": "$creation_at" },
"day": { "$day": "$creation_at" },
"hour": { "$hour": "$creation_at" }
},
"minCpu": { "$min": "$cpu" },
"maxCpu": { "$max": "$cpu" },
"avgCpu": { "$avg": "$cpu" },
"minMem": { "$min": "$mem" },
"maxMem": { "$max": "$mem" },
"avgMem": { "$avg": "$mem" }
}}
])
这是一小时的间隔,但当然有更细粒度的运算符。当然,如果没有进一步的投影,聚合字段就不能像您拥有的那样"嵌套"。但如果你愿意,你也可以这样做。
如果日期聚合运算符看起来太简洁,或者"时间戳"值更适合您,那么您可以使用日期数学:
db.collection.aggregate([
{ "$group": {
"_id": {
"$subtract": [
{ "$subtract": [ "$creation_at", new Date("1970-01-01") ] },
{ "$mod": [
{ "$subtract": [ "$creation_at", new Date("1970-01-01") ] },
1000 * 60 * 60
]}
]
},
"minCpu": { "$min": "$cpu" },
"maxCpu": { "$max": "$cpu" },
"avgCpu": { "$avg": "$cpu" },
"minMem": { "$min": "$mem" },
"maxMem": { "$max": "$mem" },
"avgMem": { "$avg": "$mem" }
}}
])
由于从日期中"减去"纪元日期"值以毫秒为单位返回当前时间作为数字。
如果你的"字符串"在这里是一个问题,你总是可以回退到 mapReduce:
db.collection.mapReduce(
function() {
var date = this.creation_at.valueOf()
- ( this.creation_at.valueOf % ( 1000 * 60 * 60 ) );
emit( new Date(date), {
cpu: {
min: parseInt(this.cpu),
max: parseInt(this.cpu),
avg: parseInt(this.cpu)
},
mem: {
min: parseFloat(this.mem),
max: parseFloat(this.mem),
avg: parseFloat(this.mem)
}
})
},
function(key,values) {
var result = {
cpu: { min: 0, max: 0, avg: 0 },
mem: { min: 0, max: 0, avg: 0 }
};
result.cpu.min = Math.min.apply( null, values.map(function(el) {
return el.cpu.min;
}));
result.cpu.max = Math.max.apply( null, values.map(function(el) {
return el.cpu.max;
}));
result.cpu.avg = Array.sum(values.map(function(el) {
return el.cpu.avg
})) / values.length;
result.mem.min = Math.min.apply( null, values.map(function(el) {
return el.mem.min;
}));
result.mem.max = Math.max.apply( null, values.map(function(el) {
return el.mem.max;
}));
result.mem.avg = Array.sum(values.map(function(el) {
return el.mem.avg
})) / values.length;
return result;
},
{ "out": { "inline": 1 } }
)
并且可能比这种快速黑客方法更好地清理化简器逻辑。
但基本原则是从日期中提取间隔以分组,然后对结果字段进行数学运算。