MongoDB按日期间隔分组

jon*_*asx 3 mongodb mongodb-query aggregation-framework

我有一个带有datetime字段和计数的集合:

{
    _id: null,
    datetime: new Date(),
    count: 1234
}
Run Code Online (Sandbox Code Playgroud)

我想以24小时,7天和30天的间隔获得计数总和.结果必须如下:

{"sum": 100, "interval": "day"},
{"sum": 700, "interval": "week"},
{"sum": 3000, "interval": "month"}
Run Code Online (Sandbox Code Playgroud)

编辑:

更抽象:我需要多个条件的组结果(在这种情况下 - 多个时间间隔)

MySQL示例:

SELECT 
    IF (time>CURRENT_TIMESTAMP() - INTERVAL 24 HOUR, 1, 0) last_day,
    IF (time>CURRENT_TIMESTAMP() - INTERVAL 168 HOUR, 1, 0) last_week,
    IF (time>CURRENT_TIMESTAMP() - INTERVAL 720 HOUR, 1, 0) last_month,
    SUM(count) count
FROM table
GROUP BY    last_day,
            last_week,
            last_month
Run Code Online (Sandbox Code Playgroud)

Nei*_*unn 17

日期汇聚运营商提供给的MongoDB的聚合框架.因此,例如,$dayOfYear运算符用于从分组中使用的日期获取该值:

db.collection.aggregate([
    { "$group": {
        "_id": { "$dayOfYear": "$datetime" },
        "total": { "$sum": "$count" }
    }}
])
Run Code Online (Sandbox Code Playgroud)

或者您可以使用日期数学方法.通过应用纪元日期,您可以将日期对象转换为可应用数学的数字:

db.collection.aggregate([
    { "$group": {
        "_id": { 
            "$subtract": [
                { "$subtract": [ "$datetime", new Date("1970-01-01") ] },
                { "$mod": [
                    { "$subtract": [ "$datetime", new Date("1970-01-01") ] },
                    1000 * 60 * 60 * 24
                ]}
            ]
        },
        "total": { "$sum": "$count" }
    }}
])
Run Code Online (Sandbox Code Playgroud)

如果您所追求的是从当前时间点开始的间隔,那么您想要的基本上是日期数学方法,并通过$cond运算符在某些条件下工作:

db.collection.aggregate([
    { "$match": {
        "datetime": { 
            "$gte": new Date(new Date().valueOf() - ( 1000 * 60 * 60 * 24 * 365 ))
        }
    }},
    { "$group": {
        "_id": null,
        "24hours": { 
            "$sum": {
                "$cond": [
                    { "$gt": [
                        { "$subtract": [ "$datetime", new Date("1970-01-01") ] },
                        new Date().valueOf() - ( 1000 * 60 * 60 * 24 )
                    ]},
                    "$count",
                    0
                ]
            }
        },
        "30days": { 
            "$sum": {
                "$cond": [
                    { "$gt": [
                        { "$subtract": [ "$datetime", new Date("1970-01-01") ] },
                        new Date().valueOf() - ( 1000 * 60 * 60 * 24 * 30 )
                    ]},
                    "$count",
                    0
                ]
            }
        },
        "OneYear": { 
            "$sum": {
                "$cond": [
                    { "$gt": [
                        { "$subtract": [ "$datetime", new Date("1970-01-01") ] },
                        new Date().valueOf() - ( 1000 * 60 * 60 * 24 * 365 )
                    ]},
                    "$count",
                    0
                ]
            }
        }
    }}
])
Run Code Online (Sandbox Code Playgroud)

它与SQL示例基本上是相同的方法,其中查询有条件地评估日期值是否在所需范围内,并决定是否将值添加到总和.

这里添加的一个附加$match阶段是限制查询仅对那些可能在您要求的最大一年范围内的项目进行操作.这使它比所提出的SQL好一点,因为可以使用索引来过滤掉这些值,并且您不需要通过集合中的非匹配数据"强力".

$match使用聚合管道时,最好限制输入.


Tom*_*ing 3

有两种不同的方法可以做到这一点。count()一种是对每个范围发出单独的查询。这非常简单,如果日期时间字段被索引,速度会很快。

第二种方法是使用与 SQL 示例类似的方法将它们全部组合到一个查询中。为此,您需要使用该aggregate()方法,创建一个管道,$project为新的“last_day”、“last_week”和“last_month”字段创建 0 或 1 值,然后使用运算符$group进行求和。