如何在MongoDB中聚合时间序列数据

如何在MongoDB中聚合时间序列数据,mongodb,time-series,aggregation-framework,Mongodb,Time Series,Aggregation Framework,我有MongoDB文档,就像这里解释的一样 因此,每天有一个文档(以及类型和系统),其中有一个values字段,其中包含小时、分钟和秒数据,如下所示: { "_id" : ObjectId("59fc57d75bc7315366b78799"), "date" : ISODate("2017-11-03T00:00:00.000+0000"), "system" : "192-168-1-30", "type" : "memory", "valu

我有MongoDB文档,就像这里解释的一样

因此,每天有一个文档(以及类型和系统),其中有一个
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


有什么提示吗?

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

“num_samples”和“total_samples”字段会随着新读数应用于文档而更新:

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

这篇文章很旧。一方面,Mongodb从那时起有了很大的发展,另一方面,上面提到的项目被放弃了。我特别为方形立方体一号的命运感到遗憾

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

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
}
在此之后,您可以按秒、分、小时将聚合阶段应用于分组

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


首先,每秒存储一个文档要简单得多。

是每60秒、1小时等存储一个文档,还是最后60秒、1小时等存储一个文档?嗯,这是什么意思?我几乎每秒都会得到数据,我希望它平均按分钟、小时等进行聚合。哦,我看到了你们所说的部分。“For each”,更新…非常感谢,所以您认为使用大量文档而不是这种(旧的)方法更有效率吗?我知道每秒保存1个文档会越来越容易,但我想我会收集大量的记录(我必须监控10k系统)。@Michelem你的后续问题一针见血。对于数据量不允许在运行时聚合数据的系统,预聚合数据是一种利基方法。如果每秒有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
}