Ответ 1
Вы начинаете думать по правильным линиям здесь, когда вы направляетесь в правильном направлении. Изменение вашего мышления SQL, "отличное", на самом деле является еще одним способом записи операции $group
на любом языке. Это означает, что вы выполняете здесь две групповые операции, а в терминах агрегирования - два этапа конвейера.
Просто с упрощенными документами для визуализации:
{
"campaign_id": "A",
"campaign_name": "A",
"subscriber_id": "123"
},
{
"campaign_id": "A",
"campaign_name": "A",
"subscriber_id": "123"
},
{
"campaign_id": "A",
"campaign_name": "A",
"subscriber_id": "456"
}
Разумеется, для данной комбинации "кампания" общий счет и "отчетливый" счет составляют "3" и "2" соответственно. Таким образом, логическая задача - сначала "группировать" все эти значения "подписчик", а также учитывать количество вхождений для каждого из них, а затем, думая "конвейер", "общее количество" этих подсчетов за "кампанию", а затем просто считайте, отличные "вхождения в виде отдельного номера:
db.campaigns.aggregate([
{ "$match": { "subscriber_id": { "$ne": null }}},
// Count all occurrences
{ "$group": {
"_id": {
"campaign_id": "$campaign_id",
"campaign_name": "$campaign_name",
"subscriber_id": "$subscriber_id"
},
"count": { "$sum": 1 }
}},
// Sum all occurrences and count distinct
{ "$group": {
"_id": {
"campaign_id": "$_id.campaign_id",
"campaign_name": "$_id.campaign_name"
},
"totalCount": { "$sum": "$count" },
"distinctCount": { "$sum": 1 }
}}
])
После первой "группы" выходные документы можно визуализировать следующим образом:
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A",
"subscriber_id" : "456"
},
"count" : 1
}
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A",
"subscriber_id" : "123"
},
"count" : 2
}
Итак, из "трех" документов в образце "2" относятся к одному отдельному значению и "1" к другому. Это можно по-прежнему суммировать с помощью $sum
, чтобы получить итоговые документы соответствия, которые вы делаете на следующем этапе, с конечным результатом:
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A"
},
"totalCount" : 3,
"distinctCount" : 2
}
Действительно хорошая аналогия для конвейера агрегации - это unix-труба "|" оператор, который позволяет "связывать" операции, чтобы вы могли передавать вывод одной команды на вход следующего и так далее. Если вы начнете думать о своих требованиях к обработке, это поможет вам лучше понять операции с конвейером агрегации.