Двойная агрегация $group в MongoDB по дате и статусу
У меня есть несколько документов, которые выглядят так (за исключением множества других нерелевантных полей):
[{
status: 'open',
createdDate: 2021-06-17T09:02:58.325Z
},
{
status: 'declined',
createdDate: 2021-07-25T09:09:15.851Z
},
{
status: 'declined',
createdDate: 2021-09-22T09:32:14.958Z
},
{
status: 'open',
createdDate: 2021-09-02T09:45:26.584Z
},
{
status: 'referral',
createdDate: 2021-09-05T09:46:02.764Z
}]
Для этой подгруппы коллекции я хочу агрегировать следующий результат:
{
"2021-06" : { submitted: 1, referral: 0, declined: 0},
"2021-07" : { submitted: 1, referral: 0, declined: 1},
"2021-08" : { submitted: 0, referral: 0, declined: 0},
"2021-09" : { submitted: 3, referral: 1, declined: 1},
}
Представлено общее количество документов (открытых, реферальных и отклоненных). Я пытался использовать $group несколькими способами, но это не сработало. Какие-либо предложения? Спасибо!
2 ответа
ОП попросил решение, в котором значения становятся ключами, например
2021-06: {...
. В духе хорошего дизайна данных я мог бы предложить более простой конвейер, который сохраняет значение даты как значение:
db.foo.aggregate([
// The SAME as answer above!
{$group: {
"_id":{"$dateToString":{"date":"$createdDate", "format":"%Y-%m"}},
"submitted":{"$sum":1},
"referral":{"$sum":{"$cond":[{"$eq":["$status", "open"]}, 1, 0]}},
"declined":{"$sum":{"$cond":[{"$eq":["$status", "declined"]}, 1, 0]}}
}}
]);
уступать
{ "_id" : "2021-06", "submitted" : 1, "referral" : 1, "declined" : 0 }
{ "_id" : "2021-07", "submitted" : 1, "referral" : 0, "declined" : 1 }
{ "_id" : "2021-09", "submitted" : 3, "referral" : 1, "declined" : 1 }
Теперь можно сортировать, фильтровать и т.д., не прибегая к превращению ключей в rval через
$objectToArray
и т. д. Если совершенно необходимо иметь более описательное имя ключа, чем (и не вызывать путаницы, сохраняя
_id
), затем добавьте эти этапы:
,{$addFields: {"date":"$_id"}}
,{$unset: "_id"}
Запрос
- группировать по дате в виде строки только с годом и месяцем
- считайте 3 аккумулятора, первый всегда добавляет, второй и третий добавляют только если видят статус открытый(второй) и статус(отклонен) третий
- замените корень и массив на объект, чтобы сделать ключ данных и данные как вложенный документ, как в ожидаемом результате
aggregate(
[{"$group":
{"_id":{"$dateToString":{"date":"$createdDate", "format":"%Y-%m"}},
"submitted":{"$sum":1},
"referral":{"$sum":{"$cond":[{"$eq":["$status", "open"]}, 1, 0]}},
"declined":
{"$sum":{"$cond":[{"$eq":["$status", "declined"]}, 1, 0]}}}},
{"$replaceRoot":
{"newRoot":
{"$arrayToObject":
[[{"k":"$_id",
"v":
{"submitted":"$submitted",
"referral":"$referral",
"declined":"$declined"}}]]}}}])