Zaczynasz myśleć we właściwym kierunku, gdy zmierzałeś we właściwym kierunku. Zmieniając sposób myślenia SQL, „odrębny” to tak naprawdę tylko kolejny sposób na napisanie $group
operacja w dowolnym języku. Oznacza to, że masz dwa operacje grupowe odbywające się tutaj i, w kategoriach potoku agregacji, dwa etapy potoku.
Tylko z uproszczonymi dokumentami do wizualizacji:
{
"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"
}
Jest rzeczą zrozumiałą, że dla danej kombinacji „kampanii” całkowita liczba i „różne” liczby wynoszą odpowiednio „3” i „2”. Logiczną rzeczą do zrobienia jest więc najpierw „zgrupowanie” wszystkich tych wartości „subscriber_id” i zachowanie liczby wystąpień dla każdej z nich, a następnie myślenie „potok”, „suma” tych wartości na „kampanię”, a następnie po prostu policz „ odrębne” wystąpienia jako oddzielna liczba:
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 }
}}
])
Po pierwszej "grupie" dokumenty wyjściowe można wizualizować w następujący sposób:
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A",
"subscriber_id" : "456"
},
"count" : 1
}
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A",
"subscriber_id" : "123"
},
"count" : 2
}
Tak więc z „trzech” dokumentów w przykładzie „2” należy do jednej odrębnej wartości, a „1” do innej. Można to nadal sumować za pomocą $sum
w celu uzyskania wszystkich pasujących dokumentów, które wykonasz w następnym etapie, z końcowym wynikiem:
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A"
},
"totalCount" : 3,
"distinctCount" : 2
}
Naprawdę dobrą analogią do potoku agregacji jest potok unixowy „|” operator, który umożliwia „łączenie w łańcuch” operacji, dzięki czemu można przekazać dane wyjściowe jednego polecenia do danych wejściowych następnego i tak dalej. Rozpoczęcie myślenia o wymaganiach przetwarzania w ten sposób pomoże ci lepiej zrozumieć operacje z potoku agregacji.