我正在为公司的生产系统开发监控系统。这意味着我将要存储的数据的性质是时间序列。在查看了其他几个数据库后,我为此选择了MongoDB。 来自生产系统的事件将一直到达,但我打算将事件存储在10分钟的间隔文档中。最终,集合中的文档将如下所示:
{
_id: '04/25/2015 13:00',
event1_count : 130,
event2_count : 50,
event3_count : 200
},
{
_id: '04/25/2015 13:10',
event1_count : 230,
event2_count : 20,
event3_count : 400
}
文档_id: '04/25/2015 13:00'
仅表示它包含2015年4月25日13:00到2015年4月25日13:10之间到达的所有事件。
最终,我希望在数据上运行不同的报告。例如 - 过去20分钟内的事件数。 我希望在最后20分钟获得事件计数的结果是:
{
event1_count : 360,
event2_count : 70,
event3_count : 600
}
我的问题 - 有没有办法在一个查询中聚合来自不同文档的多个字段?
BTW - 对我来说,以10分钟的间隔保持数据非常重要,因为其他报告需要时间分辨率。答案 0 :(得分:2)
是的,确实可以。假设您的集合将文档存储在上述结构中,您可以通过添加另一个字段date
来修改结构,该字段将_id存储为ISODate,而不是字符串时间戳,以便您可以进行聚合使用 Date operators 。要进行转换,您可以使用mongo的forEach()
游标方法与$set
运算符进行原子更新:
db.collection.find().forEach(function (doc){
var dateObject = new Date(doc._id);
db.collection.update({_id: doc._id}, { $set: { date: dateObject } });
});
以上内容将在您的文档中创建一个额外的字段date
,其中包含_id
字符串的ISODate对象表示。
假设您在上面的更新后现在在您的集合中有以下示例文档:
/* 0 */
{
"_id" : "04/25/2015 13:00",
"event1_count" : 130,
"event2_count" : 50,
"event3_count" : 200,
"date" : ISODate("2015-04-25T13:00:00.000Z")
}
/* 1 */
{
"_id" : "04/25/2015 13:10",
"event1_count" : 230,
"event2_count" : 20,
"event3_count" : 400,
"date" : ISODate("2015-04-25T13:10:00.000Z")
}
/* 2 */
{
"_id" : "04/25/2015 13:20",
"event1_count" : 240,
"event2_count" : 30,
"event3_count" : 350,
"date" : ISODate("2015-04-25T13:20:00.000Z")
}
/* 3 */
{
"_id" : "04/25/2015 13:30",
"event1_count" : 180,
"event2_count" : 60,
"event3_count" : 500,
"date" : ISODate("2015-04-25T13:30:00.000Z")
}
以下聚合管道将根据20分钟的间隔为您提供所需的结果:
var interval = 20,
pipeline = [
{
"$group": {
"_id": {
"year": { "$year": "$date" },
"dayOfYear": { "$dayOfYear": "$date" },
"interval": {
"$subtract": [
{ "$minute": "$date" },
{ "$mod": [{ "$minute": "$date" }, interval ] }
]
}
},
"event1_count": { "$sum": "$event1_count" },
"event2_count": { "$sum": "$event2_count" },
"event3_count": { "$sum": "$event3_count" }
}
},
{
"$project": {
"_id": 0,
"event1_count": 1,
"event2_count": 1,
"event3_count": 1
}
}
];
db.collection.aggregate(pipeline);
<强>输出强>:
/* 0 */
{
"result" : [
{
"event1_count" : 420,
"event2_count" : 90,
"event3_count" : 850
},
{
"event1_count" : 360,
"event2_count" : 70,
"event3_count" : 600
}
],
"ok" : 1
}