【问题标题】:time series data in mongodb - how to query embedded documentmongodb中的时间序列数据-如何查询嵌入文档
【发布时间】:2015-05-03 00:33:52
【问题描述】:

我正在设计一个时间序列数据集,基本上我有我监控的服务器,我想知道一段时间内关于它的一些指标。 基于http://blog.mongodb.org/post/65517193370/schema-design-for-time-series-data-in-mongodb 我创建了一个设计,它是每个服务器 + 月的一个文档,其中每天嵌入一个文档,每小时嵌入一个文档,其中包含指标。

所以为某个服务器插入两个小时的数据看起来像这样:

-- 用于服务器 i-09484d47 和日期 2015/02/23 小时 16

db.servers.update(
  { _id : "i-09484d47_201502",
    service: "AWS/EC2",
    owner : "gil"
  }, 
  {$set: {"values.23.16.samples": 60 ,"values.23.16.average": 0.33883, "values.23.16.minimum": 0.16, "values.23.16.maximum": 0.67} },
  { upsert: true }
)

-- 用于服务器 i-09484d47 和日期 2015/02/23 小时 17

db.servers.update(
  { _id : "i-09484d47_201502",
    service: "AWS/EC2",
    owner : "gil"
  }, 
  {$set: {"values.23.17.samples": 60 ,"values.23.17.average": 0.6, "values.23.17.minimum": 0.5, "values.23.17.maximum": 0.8} },
  { upsert: true }
)

等等。

现在我想获取特定服务器的所有数据,在给定的日期范围内,比如某个星期(假设它包含在一个月内)。 我不想拉整个文档并在客户端上进行过滤。 有什么想法吗?

【问题讨论】:

  • 为什么不把更新的日期保存在你的文档中,用它来查询你的数据库呢?
  • 没看懂你的问题,能详细点吗?

标签: mongodb time-series


【解决方案1】:

由于您在键中指定了时间和日期,因此您可以通过投影要显示的键来执行此操作。所以如果你想要从 2 月 16 日到 22 日这一周,你可以这样做:

db.servers.find(
    { "_id": "i-09484d47_201502" },
    {
        "values.16": 1,
        "values.17": 1,
        "values.18": 1,
        "values.19": 1,
        "values.20": 1,
        "values.21": 1,
        "values.22": 1
    }
);

您可以看到手动输入是多么痛苦,因此您可能希望使用一个函数来返回给定日期范围的投影对象。在同一个月内,在 JavaScript 中,它会像这样工作:

function generateProjection(start, end) {

    obj = {};
    prefix = "values";

    for (var i = start; i <= end; i++) {
        var key = prefix + "." + i;
        obj[key] = 1;
    }

    return obj;
}

然后您可以按如下方式使用:

var proj = generateProjection(16, 22);
db.servers.find({ "_id": "i-09484d47_201502" }, proj);

如果您愿意,只需稍作改动,您就可以添加多个月和数小时的支持。另一种方法是更改​​您的架构,以便将有关日期的信息包含为一个值,并且可能将每个子文档存储在一个数组中,以便您可以利用 aggregation 中的 $unwind 运算符。

PS。有点离题,但鉴于_id 是唯一的,您无需在更新查询中指定所有匹配条件。您可以将其简化为以下内容:

编辑: 添加了$setOnInsert 子句以涵盖upsert 所需的字段。

db.servers.update(
  { "_id": "i-09484d47_201502" }, 
  { "$set": { ... },
  { "$setOnInsert": { "service": "AWS/EC2", "owner": "gil" } },
  { "upsert": true }
);

【讨论】:

  • 我认为其中的附加字段的点是因为upsert 操作,因此它们将在新文档中创建。如果它们未更改,现代版本实际上不应“更新”这些字段(至少它们不会在批量 API 方法下报告为已修改),但可能更好的替代意图是 $setOnInsert,它仅适用于文档创建.
  • 太棒了!非常感谢您的详细回答。一些事情: - 你到底是什么意思将日期存储为值?它不是已经这样了吗? - 将 subdoc 视为数组,如果我需要访问某一天,我怎么知道哪个数组单元包含它?并非每个文档都包含所有日期(例如,如果数据在月中开始出现),所以我不能假设总是有大约 30 个子文档。
  • 很高兴它有帮助!我的意思是,如果您将文档视为{ key: value } 对,那么您将告诉您日期/时间的信息存储在key 中,而不是value。另一种方法是将您的values 字段作为一个数组,其中包含~30 天 * 24 小时 = 720 个包含当前信息的子文档(samplesaverage 等)加上dayhour。因此,您可以使用点表示法查询该数组。
  • 如果我使用数组以便每个小时都是一个单元格,我如何向其中添加数据,这意味着我想要进行 upsert - 如果文档不存在 - 创建它并创建它如果文档确实存在但该数组单元格不存在则一个单元格 - 创建该数组单元格注意我不必处理更新现有单元格,它只插入。
猜你喜欢
  • 2018-03-20
  • 2021-03-24
  • 1970-01-01
  • 2021-01-23
  • 2015-08-30
  • 2021-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多