Тук започвате да мислите в правилните линии, докато сте се насочили в правилната посока. Промяната на вашето мислене на 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“. Така че логичното нещо, което трябва да направите, е първо да „групирате“ всички тези стойности на „subscriber_id“ и да запазите броя на събитията за всяка, след това докато мислите за „тръбопровод“, „общо“ тези бройки за „кампания“ и след това просто пребройте „ различни" поява като отделно число:
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 тръбата "|" оператор, който позволява "верижно свързване" на операции, така че да можете да прехвърлите изхода на една команда към входа на следващата и т.н. Ако започнете да мислите за вашите изисквания за обработка по този начин, това ще ви помогне да разберете по-добре операциите с конвейера за агрегация.