So I have some data which looks like this:
[
{
"_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
and signaler
can be any strings, status
must be one of alarm
, warning
or normal
.
I want to write an aggregation which groups on signaler
+ key
and tells me the total alarms and warnings for 3 durations: all time, last week and last month.
Expected output:
[
{
"_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
}
]
I know how to write the group stage which calculates the warnings and alarms for all time but I'm not sure how to do the time bucketing, especially since they are 'stacked' i.e the counts of last week will also be in the counts for last month.
The group step as far I understand:
[
{
"$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
}
}
]
To illustrate Fanamy's answer, here's the group stage used to achieve this :
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 }}
}
}}
])