MongoDB - 在一个查询中聚合多个字段

时间:2015-04-25 15:42:59

标签: mongodb

我正在为公司的生产系统开发监控系统。这意味着我将要存储的数据的性质是时间序列。在查看了其他几个数据库后,我为此选择了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分钟的间隔保持数据非常重要,因为其他报告需要时间分辨率。

1 个答案:

答案 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
}