【问题标题】:MongoDB - aggregate multiple fields in one queryMongoDB - 在一个查询中聚合多个字段
【发布时间】:2015-04-26 02:37:14
【问题描述】:

我正在为我们公司的生产系统开发一个监控系统。这意味着我将存储的数据的性质是时间序列的。在查看了其他几个数据库之后,我为此选择了 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' 仅表示它包含在 04/25/2015 13:00 和 04/25/2015 13:10 之间到达的所有事件。

最终,我希望在数据上运行不同的报告。例如 - 最近 20 分钟内的事件计数。 我想在过去 20 分钟内获得的事件计数结果是:

{
event1_count : 360,
event2_count : 70,
event3_count : 600
}

我的问题 - 有没有办法在一个查询中聚合来自不同文档的多个字段?

顺便说一句 - 将数据保持在 10 分钟间隔对我来说很重要,因为其他报告将需要该时间分辨率。

【问题讨论】:

  • 在我的问题中,您可以看到 2 个文档。每个文档都有几个字段 - event1_count、event2_count 等。我想对两个文档中的 event_count1 求和,对于 event_count2 也是如此。所以结果应该是 event_count1 的总和,event_count2 的总和等等。我正在寻找一种在一个查询中执行此操作的方法,假设我会有很多其他事件,而不仅仅是我的示例中的 3 个。

标签: mongodb


【解决方案1】:

是的,这确实是可能的。假设您的集合将在上述结构中存储文档,您可以通过添加另一个字段来修改结构,例如 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
}

【讨论】:

  • @assafm 别担心 :-)
猜你喜欢
  • 1970-01-01
  • 2021-10-09
  • 2018-06-16
  • 2021-05-27
  • 1970-01-01
  • 2020-07-15
  • 2023-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多