【问题标题】:How can I aggregate documents by time interval in MongoDB?如何在 MongoDB 中按时间间隔聚合文档?
【发布时间】:2014-02-15 05:52:12
【问题描述】:

我需要根据某个时间间隔汇总我的收藏。

如您所想,我不需要计算,例如我们每天的每小时。

我需要根据 30 分钟间隔(或任何其他时间间隔)进行汇总。可以说,第一个文档是在下午 3:45 创建的。然后在下午 3:45 到下午 4:15 之间创建了另外 5 个文档。 所以在这个时间间隔内,我有 6 个文档。所以 MapReduce 结果的第一个文档是计数为 6 的文档。

假设下一个文档是在下午 4:35 创建的广告,另外三个是在下午 4:40 创建的。

所以 MapReduce 结果的下一个文档是计数为 4 的文档。

等等……

目前我的地图功能是这样的:

var map = function() {                                    
        var key = {name: this.name, minute: this.timestamp.getMinutes()};
        emit(key, {count: 1})
};

所以没什么特别的。目前我按分钟分组,这不是我最后想要的。在这里,我需要能够检查上述时间间隔,而不是分钟。

还有我的reduce函数:

var reduce = function(key, values)
{
   var sum = 0;
   values.forEach(function(value)
   {
       sum += value['count'];
   });
   return {count: sum};
};

这样的输出是这样的:

{
0: "{ "_id" : { "name" : "A" , "minute" : 11.0} , "value" : { "count" : 1.0}}",
1: "{ "_id" : { "name" : "B" , "minute" : 41.0} , "value" : { "count" : 6.0}}",
2: "{ "_id" : { "name" : "B" , "minute" : 42.0} , "value" : { "count" : 3.0}}",
3: "{ "_id" : { "name" : "C" , "minute" : 41.0} , "value" : { "count" : 2.0}}",
4: "{ "_id" : { "name" : "C" , "minute" : 42.0} , "value" : { "count" : 2.0}}",
5: "{ "_id" : { "name" : "D" , "minute" : 11.0} , "value" : { "count" : 1.0}}",
6: "{ "_id" : { "name" : "E" , "minute" : 16.0} , "value" : { "count" : 1.0}}"
}

所以它每分钟计算/聚合文档,但不是按我的自定义时间间隔。

对此有什么想法吗?

【问题讨论】:

    标签: mongodb mapreduce aggregation-framework


    【解决方案1】:

    编辑:我使用 map reduce 的示例不起作用,但我认为这大致完成了您想要做的事情。 我使用 project 来定义一个变量 time 以包含从您的时间戳四舍五入到 5 分钟间隔的分钟。使用整数除法会很容易,但我认为 mongodb 查询语言目前不支持,所以我从分钟中减去 minutes mod 5 以获得每 5 分钟更改一次的数字。然后按名称的组和这个时间计数器应该可以解决问题。

    query = [
        {   
            "$project": {
                "_id":"$_id",
                "name":"$name",
                "time": {
                    "$subtract": [
                        {"$minute":"$timestamp"},
                        {"$mod": [{"$minute":"$timestamp"}, 5]}
                    ]
                }
            }
        },
        {   
            "$group": {"_id": {"name": "$name", "time": "$time"}, "count":{"$sum":1}}
        }
    ]
    db.foo.aggregate(query)
    

    【讨论】:

    • 谢谢,但这不起作用。比方说,我们使用您的方法与 30 (Math.floor(timestamp.getMinutes() / 30),意味着我们只能按半小时分组。所以下午 14:25 和下午 14:35 的文档将被计算两次跨度>
    • 我编辑了我的评论。我认为它应该工作。 14:25 的文档将位于 25 div 30 = 0 括号中,14:35 分钟的文档将位于 35 div 30 = 1 分钟的括号中。为清楚起见,您可以使用30 * Math.floor(timestamp.getMinutes() / 30)。当然,根据您的数据集,为小时、日、月、年添加一个因子可能是有意义的,否则 14:35 和 15:35 最终会出现在同一个括号中
    • 您想从任意起点而不是从小时开始按 30 分钟的时间段进行聚合吗?那么从 14:35 到 15:05 这段时间?
    • 是的!感谢您的快速响应,但仍然是同样的问题。我只能分组 30 分钟间隔。这是我的测试:gist.github.com/sebastian-alfers/74014d45a6dd3f47a72f
    • 在这种情况下,您可以按第一个文档的this.timestamp.getMinutes() minus the timestamp.getMinutes() 分组,然后将这些分钟重新添加到结果中的时间。我想不出在一个查询中做到这一点的方法。我会分两步做:第一次查询最旧的文档,然后执行第二次查询,您发出的时间戳减去最旧文档的时间戳。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多