我在academic research project,并使用MongoDB存储加速度计值(IoT /遥测数据)的时间序列数据。粒度是样本,其中采样率可以是1到100Hz之间的任何值。目前我每个文档使用一小时的数据,然后是三维数组,第一级是分钟,第二级是秒,第三级是样本(双数据类型)。这得益于MongoDB的时间序列数据演示(Part 1,Part 2)。
e.g。
{
"_id": "2018011200:4", /* Jan 12, 2018 hour 00 UTC for sensor 4 */
"z": [
00: [ /* 00h00m */
00: [ 0.1, 0.0, -0.1, ... ], /* 00h00m00s */
01: [ 0.1, 0.0, -0.1, ... ], /* 00h00m01s */
02: [ 0.1, 0.0, -0.1, ... ], /* 00h00m02s */
...
59: [ 0.1, 0.0, -0.1, ... ] /* 00h00m59s */
], ...
]
}
通过这种方式,使用$slice
获取数据子集只能在分钟级别完成,例如,如果我想从00:00:00到00:00:01获取数据,我需要从MongoDB获取00:00(包含60秒)的整分钟,然后在应用程序中获取我需要的第二个。此外,如果我想从00:00:59到00:01:01获取数据,那么我需要整整两分钟,然后在每个应用程序子集中将它们合并回来。这有一点IO浪费,在应用程序中也有一些复杂性。顺便说一句,我不需要检索单个样本,最小的检索单位(和存储)是第二个。
我正在考虑一种稍微不同的方法,其中小时文档被直接划分为几秒钟的数组(因为一小时内有3600秒),然后是样本数组。这意味着要获得5秒的数据,我将检索恰好5秒的数组(即使在两个不同的文档中,如果时间范围超过小时)。仍然存在在不同文档中合并两部分秒的应用程序逻辑,但比小时/分钟/秒层次结构简单。
{
"_id": "2018011200:4", /* Jan 12, 2018 hour 00 UTC for sensor 4 */
"z": [
0: [ 0.1, 0.0, -0.1, ... ], /* 00h00m00s */
1: [ 0.1, 0.0, -0.1, ... ], /* 00h00m01s */
2: [ 0.1, 0.0, -0.1, ... ], /* 00h00m02s */
...
3599: [ 0.1, 0.0, -0.1, ... ] /* 00h59m59s */
]
}
但是,我也担心替代方法存在我不知道的弱点。
你推荐哪一个更好?我需要考虑哪些潜在的陷阱?或许我应该考虑另一种设计?
提前谢谢。
答案 0 :(得分:1)
我认为你的数据模型过于复杂。
更新文档要比简单地插入文档复杂得多。由于您的粒度似乎是秒,我们完全在BSON datatype UTC datetime提供的粒度范围内:它精确到毫秒。
因此,根据您的数据模型,假设您为每次写入获得单个值,只需使用类似的内容:
{
_id: new ObjectId(),
value: 0.1,
sensor: 4,
ts: new ISODate()
}
使用此数据模型,我们确保写入尽可能便宜,而不会牺牲信息。然后,您可以使用MongoDB's aggregations在数据中查询有趣的值。一个简单的例子是计算2018-01-01T00:00:00.000Z和2018-01-02T23:59:59.999Z之间传感器4的值数:
db.values.aggregate([
{"$match":{"sensor":4,"ts":{"$gte":ISODate("2018-01-01"),"$lt":ISODate("2018-01-02")}}},
{"$sort":{"ts":-1}},
{ "$group": {
"_id": {
"year": { "$year": "$ts" },
"dayOfYear": { "$dayOfYear": "$ts" },
"hourOfDay": {"$hour":"$ts"},
"minuteOfHour": {"$minute":"$ts"},
"secondOfMinute": {
"$subtract": [
{ "$second": "$ts" },
{ "$mod": [{ "$second": "$ts"}, 1] }
]
}
},
"count": { $sum: 1 }
}},
],{"allowDiskUse":true})
更好的是,您可以使用$out
stage保存您的聚合,以便更快地访问。
编辑:请注意,您必须正确使用索引才能使此方法更有效。就其本身而言,即使使用我相当有限的50M样本文档测试集,聚合也需要几秒钟。通过索引,我们谈论大约80毫秒,给你一个印象。