MongoDB Aggregations - разделите данные на временные интервалы - PullRequest
0 голосов
/ 21 сентября 2018

Итак, у меня есть некоторые данные, которые выглядят так:

[
    {
        "_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"
    }
]

key и signaler могут быть любыми строками, status должно быть одним из alarm, warning или normal.

Я хочу написать агрегацию, которая группируется по 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       
    }
]

Я знаю, как написать групповую стадию, которая рассчитывает предупреждения и аварийные сигналы за все время, но я не уверен, как сделать разбивку по времени, тем более что они «сложены», т.е.подсчеты за прошлую неделю также будут учитываться в подсчете за прошлый месяц.

Шаг группы, насколько я понимаю:

[
    { 
        "$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
        }
    }
]

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Чтобы проиллюстрировать ответ Фанами, вот групповой этап, используемый для достижения этого:

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 }}
    }
  }}
])
0 голосов
/ 21 сентября 2018

для временных интервалов, которые вы можете использовать https://docs.mongodb.com/manual/reference/method/Date/ в сочетании с $ subtract (поскольку он поддерживает даты) https://docs.mongodb.com/manual/reference/operator/aggregation/subtract/

, поэтому просто возьмите текущую дату, вычтите 7 дней или 30 длямесяц (он не будет действительно «правильным по месяцу») и проверьте, является ли дата документа ниже вашей созданной даты.

...