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

时间:2015-06-18 14:26:08

标签: node.js mongodb aggregation-framework

我现在坚持这个。 我的收藏品如下:

{ 
    "_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 docs中我发现这可以通过聚合框架实现,但我仍然坚持生成时间间隔。 你能建议我吗?

1 个答案:

答案 0 :(得分:1)

好的内存在您的数据中显示为“字符串”,因此除非您转换它,否则将会出现问题。对于数值,对于Date Aggregation Operators

的聚合框架来说这很容易
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 } }
)

并且可能比快速的hacky方法更好地清理减速器逻辑。

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