Vous commencez à penser dans la bonne direction alors que vous alliez dans la bonne direction. Changer votre état d'esprit SQL, "distinct" n'est vraiment qu'une autre façon d'écrire un $group
fonctionnement dans l'une ou l'autre langue. Cela signifie que vous avez deux les opérations de groupe qui se déroulent ici et, en termes de pipeline d'agrégation, deux étapes de pipeline.
Juste avec des documents simplifiés à visualiser :
{
"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"
}
Il va de soi que pour la combinaison "campagne" donnée, le nombre total et le nombre "distinct" sont respectivement "3" et "2". Donc, la chose logique à faire est de "regrouper" d'abord toutes ces valeurs "subscriber_id" et de conserver le nombre d'occurrences pour chacune, puis tout en pensant "pipeline", "totaliser" ces décomptes par "campagne", puis compter simplement le " occurrences "distinctes" sous la forme d'un numéro distinct :
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 }
}}
])
Après le premier "groupe", les documents de sortie peuvent être visualisés comme ceci :
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A",
"subscriber_id" : "456"
},
"count" : 1
}
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A",
"subscriber_id" : "123"
},
"count" : 2
}
Ainsi parmi les « trois » documents de l'échantillon, « 2 » appartient à une valeur distincte et « 1 » à une autre. Cela peut toujours être totalisé avec $sum
afin d'obtenir le total des documents correspondants que vous faites à l'étape suivante, avec le résultat final :
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A"
},
"totalCount" : 3,
"distinctCount" : 2
}
Une très bonne analogie pour le pipeline d'agrégation est le tube unix "|" , qui permet le "chaînage" des opérations afin que vous puissiez passer la sortie d'une commande à l'entrée de la suivante, et ainsi de suite. Commencer à réfléchir à vos exigences de traitement de cette manière vous aidera à mieux comprendre les opérations avec le pipeline d'agrégation.