【问题标题】:How to aggregate time series data in MongoDB如何在 MongoDB 中聚合时间序列数据
【发布时间】:2018-04-16 08:03:39
【问题描述】:

我有 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 吗?

有什么提示吗?

【问题讨论】:

  • 每个 60秒、1小时等等,还是持续 60秒、1小时等等?
  • 嗯,你是什么意思?我几乎每秒都会获得数据,我希望将其按分钟、小时等平均汇总。
  • 哦,我看到了你所说的部分。 “对于每个”,正在更新...

标签: mongodb time-series aggregation-framework


【解决方案1】:

您错过了文章的要点,该文章基本上描述了具有预聚合数据的系统:

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

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

因此每个文档包含每个文档的值的数量和值的总数。因此,如果您将这 2 个字段添加到文档中,您可以通过将 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 个文档可能越来越容易,但我认为我会收集大量记录(我必须监控 10k 个系统)。
  • @Michelem 你对这个后续问题一针见血。对于数据量不允许在运行时聚合它的系统,预聚合数据是一种利基方法。如果每秒有 1 个文档导致聚合速度太慢,那么答案中的代码将无济于事,因为它的成本更高。您可能希望基于每分钟预先聚合并执行更高级别的聚合运行时。
猜你喜欢
  • 1970-01-01
  • 2015-10-11
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多