MongoDB 聚合 - 将数据分成时间段

MongoDB Aggregations - Divide data into time buckets

所以我有一些数据如下所示:

[
    {
        "_id": "5ba41d8c5f60a647fc792c28",
        "key": "CPU Usage",
        "signaler": "lookup",
        "time": "2018-09-20T22:22:04.515Z",
        "status": "alarm"
    },
    {
        "_id": "5ba41d8c5f60a647fc792c2a",
        "key": "NETWORK Usage",
        "signaler": "engine",
        "time": "2018-09-20T22:22:04.516Z",
        "status": "warning"
    },
    {
        "_id": "5ba41d8c5f60a647fc792c29",
        "key": "NETWORK Usage",
        "signaler": "engine",
        "time": "2018-09-09T22:22:04.516Z",
        "status": "alarm"
    },
    {
        "_id": "5ba41d8c5f60a647fc792c2d",
        "key": "CPU Usage",
        "signaler": "evaluator",
        "time": "2018-09-09T22:22:04.840Z",
        "status": "alarm"
    },
    {
        "_id": "5ba41d8c5f60a647fc792c2b",
        "key": "RAM Usage",
        "signaler": "engine",
        "time": "2018-09-01T22:22:04.840Z",
        "status": "alarm"
    }
]

keysignaler可以是任意字符串,status必须是alarmwarningnormal之一。

我想写一个聚合,它在 signaler + key 上分组并告诉我 3 个持续时间的总警报和警告:所有时间、上周和上个月。

预期输出:

[
    {
        "_id": {
            "signaler": "lookup",
            "key": "CPU Usage"
        },
        "alarmsWeek": 1,
        "warningsWeek": 0,
        "alarmsMonth": 1,
        "warningsMonth": 0,
        "alarmsAllTime": 1,
        "warningsAllTime": 0
    },
    {
        "_id": {
            "signaler": "engine",
            "key": "Network Usage"
        },
        "alarmsWeek": 0,
        "warningsWeek": 1,
        "alarmsMonth": 1,
        "warningsMonth": 1,
        "alarmsAllTime": 1,
        "warningsAllTime": 1       
    },
    {
        "_id": {
            "signaler": "evaluator",
            "key": "CPU Usage"
        },
        "alarmsWeek": 0,
        "warningsWeek": 0,
        "alarmsMonth": 1,
        "warningsMonth": 0,
        "alarmsAllTime": 1,
        "warningsAllTime": 0       
    },
    {
        "_id": {
            "signaler": "engine",
            "key": "RAM Usage"
        },
        "alarmsWeek": 0,
        "warningsWeek": 0,
        "alarmsMonth": 0,
        "warningsMonth": 0,
        "alarmsAllTime": 1,
        "warningsAllTime": 0       
    }
]

我知道如何编写小组赛阶段计算所有时间的警告和警报,但我不确定如何进行时间分桶,尤其是因为它们是 'stacked' 即上周的计数也将计入上个月的统计。

据我了解的组步骤:

[
    { 
        "$group": { 
            "_id": { 
                "signaler":"$signaler",
                "key": "$key"

            }, 
            "totalWarnings": {
                "$sum": {
                    "$cond": [
                        {"$eq": [ "warning", "$level" ] },
                        1,
                        0
                    ]
                } 
            }, 
            "totalAlarms": {
                "$sum": {
                    "$cond": [
                        {"$eq": [ "alarm", "$level" ] },
                        1,
                        0
                    ]
                } 
            }
        } 
    },
    {
        "$project": { 
            "_id": { "$concat": ["$_id.key", "+", "$_id.signaler"] },
            "key": "$_id.key",
            "signaler": "$_id.signaler",
            "totalAlarms": 1,
            "totalWarnings": 1
        }
    }
]

您可以使用的时间段 https://docs.mongodb.com/manual/reference/method/Date/ in combination with $subtract (as it supports dates) https://docs.mongodb.com/manual/reference/operator/aggregation/subtract/

所以只需使用当前日期,减去 7 天或一个月减去 30 天(实际上不会 "month-correct")并检查文档的日期是否早于您的创建日期。

为了说明 Fanamy 的回答,这是用于实现此目的的小组赛阶段:

db.collection.aggregate([
  { "$group": {
    "_id": { "signaler": "$signaler", "key": "$key" },
    "alarmsWeek": {
      "$sum": {
        "$cond": {
          "if": {
            "$and": [
              { "$eq": ["$status", "alarm"] },
              { "$lt": ["$time", { "$subtract": [new Date(), { "$multiply": [1000, 3600, 24, 7] }] }] }
            ]
          },
          "then": 1,
          "else": 0
        }
      }
    },
    "warningsWeek": {
      "$sum": {
        "$cond": {
          "if": {
            "$and": [
              { "$eq": ["$status", "warning"] },
              { "$lt": ["$time", { "$subtract": [new Date(), { "$multiply": [1000, 3600, 24, 7] }] }] }
            ]
          },
          "then": 1,
          "else": 0
        }
      }
    },
    "alarmsMonth": {
      "$sum": {
        "$cond": {
          "if": {
            "$and": [
              { "$eq": ["$status", "alarm"] },
              { "$lt": ["$time", { "$subtract": [new Date(), { "$multiply": [1000, 3600, 24, 30] }] }] }
            ]
          },
          "then": 1,
          "else": 0
        }
      }
    },
    "warningsMonth": {
      "$sum": {
        "$cond": {
          "if": {
            "$and": [
              { "$eq": ["$status", "warning"] },
              { "$lt": ["$time", { "$subtract": [new Date(), { "$multiply": [1000, 3600, 24, 30] }] }] }
            ]
          },
          "then": 1,
          "else": 0
        }
      }
    },
    "alarmsAllTime": {
      "$sum": { "$cond": { "if": { "$eq": ["$status", "alarm"] }, "then": 1, "else": 0 }}
    },
    "warningsAllTime": {
      "$sum": { "$cond": { "if": { "$eq": ["$status", "warning"] }, "then": 1, "else": 0 }}
    }
  }}
])