如何在MongoDB中汇总时间序列数据

时间:2017-11-03 14:38:37

标签: mongodb time-series aggregation-framework

我有MongoDB文档,如https://www.mongodb.com/blog/post/schema-design-for-time-series-data-in-mongodb

所述

每天(和类型和系统)的1个文档,其中values字段包含小时,分钟和秒数据,所以这样:

{ 
    "_id" : ObjectId("59fc57d75bc7315366b78799"), 
    "date" : ISODate("2017-11-03T00:00:00.000+0000"), 
    "system" : "192-168-1-30", 
    "type" : "memory", 
    "values" : {
        [...]
        "11" : { // hour 11
            [...]
            "49" : { // minute 49
                [...]
                "43" : NumberInt(62171000), // second 43
                "44" : NumberInt(62169000),
                [...]
            }, 
            "50" : {
                "1" : NumberInt(62363000), 
                "2" : NumberInt(62319000)
                [...]
            },
            [...]
        },
        [...]
    }, 
    "updatedAt" : ISODate("2017-11-03T13:34:00.720+0000"), 
    "createdAt" : ISODate("2017-11-03T11:49:43.442+0000")
}

例如,在2017-11-03的11:49:43,记忆是在62171000。

现在我正在尝试获取这些文档的聚合数据,以获取每分钟,小时等平均数据的行,但我很困惑如何告诉聚合框架$ values是一个小时数组,分钟和秒钟。

或者我应该使用map / reduce?

任何提示?

1 个答案:

答案 0 :(得分:3)

您缺少本文的基本要点,它基本上描述了具有预聚合数据的系统:

  

当新的读数应用于文档时,字段“num_samples”和“total_samples”会更新:

{$set: {“values.59”: 2000000 }},
{$inc: {num_samples: 1, total_samples: 2000000 }}

这样每个文档都包含多个值和每个文档的总值。因此,如果您将这两个字段添加到文档中,则可以通过将total_values除以number_values轻松计算每日平均值。

这篇文章很老了。从那时起Mongodb从一方面显着发展,从另一方面提到那里的项目被抛弃了。我特别感谢Square Cube的命运。

从v3.4开始,您可以从objectToArray中受益,以实现运行时分组,如下所示:

db.collection.aggregate([
    {$project:{        
        date : 1, system : 1, type : 1,
        hour: {$objectToArray: "$values" } 
    }},
    {$unwind: "$hour"},    
    {$project:{ 
        date : 1, system : 1, type : 1,
        hour: "$hour.k",
        minute: {$objectToArray: "$hour.v" } 
    }},
    {$unwind: "$minute"},    
    {$project:{ 
        date : 1, system : 1, type : 1, hour: 1,
        minute: "$minute.k",
        second: {$objectToArray: "$minute.v" } 
    }},
    {$unwind: "$second"},    
    {$project:{ 
        date : 1, system : 1, type : 1, hour: 1, minute: 1,
        second: "$second.k",
        value: "$second.v"
    }},
])

以下列格式每秒为您提供1个文档:

{
    "_id" : ObjectId("59fc57d75bc7315366b78799"),
    "date" : ISODate("2017-11-03T00:00:00.000Z"),
    "system" : "192-168-1-30",
    "type" : "memory",
    "hour" : "11",
    "minute" : "49",
    "second" : "43",
    "value" : 62171000
}

您可以在此之后应用聚合阶段,按秒,分钟,小时进行分组。

问题是它非常昂贵,而且小时,分钟和秒都是字符串,这只会使操作变得更加复杂。

首先,每秒存储1个文档会更简单。