如何使用具有时间间隔的 nodejs 的 mongodb 驱动程序聚合文档



我目前被困在这个上面。我有这样的收藏:

{ 
    "_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 } }
)

并且可能比这种快速黑客方法更好地清理化简器逻辑。

但基本原则是从日期中提取间隔以分组,然后对结果字段进行数学运算。

相关内容

  • 没有找到相关文章

最新更新