mongodb 中的时间序列数据 - 如何查询嵌入文档
time series data in mongodb - how to query embedded document
我正在设计一个时间序列数据集,基本上我有我监控的服务器,我想知道一段时间内关于它的一些指标。
基于 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 }
)
等等。
现在我想获取特定服务器的所有数据,在给定的日期范围内,比如说某个星期(假设它包含在一个月内)。
我不想提取整个文档并在客户端上进行过滤。
有什么想法吗?
由于您在按键中指定了时间和日期,因此您可以通过投影要显示的按键来实现。所以如果你想要从 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
}
);
您可以看到手动输入是多么痛苦,因此您可能希望使用 returns 给定日期范围的投影对象的函数。在同一个月内,在 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);
稍作改动,您可以根据需要添加对多个月份和多个小时的支持。另一种方法是更改您的架构,以便将有关日期的信息包含为一个值,并且可能将每个子文档存储在一个数组中,以便您可以利用 $unwind
中的运算符 aggregation
.
PS。有点偏离主题,但鉴于 _id
是唯一的,您不需要在更新查询中指定所有匹配条件。您可以将其简化为如下所示:
编辑:
添加了 $setOnInsert
子句以涵盖 upsert
.
所需的字段
db.servers.update(
{ "_id": "i-09484d47_201502" },
{ "$set": { ... },
{ "$setOnInsert": { "service": "AWS/EC2", "owner": "gil" } },
{ "upsert": true }
);
我正在设计一个时间序列数据集,基本上我有我监控的服务器,我想知道一段时间内关于它的一些指标。 基于 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 }
)
等等。
现在我想获取特定服务器的所有数据,在给定的日期范围内,比如说某个星期(假设它包含在一个月内)。 我不想提取整个文档并在客户端上进行过滤。 有什么想法吗?
由于您在按键中指定了时间和日期,因此您可以通过投影要显示的按键来实现。所以如果你想要从 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
}
);
您可以看到手动输入是多么痛苦,因此您可能希望使用 returns 给定日期范围的投影对象的函数。在同一个月内,在 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);
稍作改动,您可以根据需要添加对多个月份和多个小时的支持。另一种方法是更改您的架构,以便将有关日期的信息包含为一个值,并且可能将每个子文档存储在一个数组中,以便您可以利用 $unwind
中的运算符 aggregation
.
PS。有点偏离主题,但鉴于 _id
是唯一的,您不需要在更新查询中指定所有匹配条件。您可以将其简化为如下所示:
编辑:
添加了 $setOnInsert
子句以涵盖 upsert
.
db.servers.update(
{ "_id": "i-09484d47_201502" },
{ "$set": { ... },
{ "$setOnInsert": { "service": "AWS/EC2", "owner": "gil" } },
{ "upsert": true }
);