Sie fangen an, hier in die richtige Richtung zu denken, da Sie in die richtige Richtung gegangen sind. Wenn Sie Ihre SQL-Denkweise ändern, ist "distinct" eigentlich nur eine andere Art, eine $group
zu schreiben Betrieb in beiden Sprachen. Das heißt, Sie haben zwei Gruppenoperationen, die hier stattfinden, und, in Bezug auf die Aggregationspipeline, zwei Pipelinephasen.
Nur mit vereinfachten Dokumenten zur Visualisierung:
{
"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"
}
Es liegt nahe, dass für die gegebene „Kampagnen“-Kombination die Gesamtanzahl und die „eindeutige“ Anzahl „3“ bzw. „2“ sind. Die logische Vorgehensweise ist also, zuerst alle diese „subscriber_id“-Werte zu „gruppieren“ und die Anzahl der Vorkommen für jeden festzuhalten, dann, während Sie an „Pipeline“ denken, diese Anzahl pro „Kampagne“ zu „summieren“ und dann einfach die „ eindeutige" Vorkommen als separate Nummer:
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 }
}}
])
Nach der ersten "Gruppe" können die Ausgabedokumente wie folgt visualisiert werden:
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A",
"subscriber_id" : "456"
},
"count" : 1
}
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A",
"subscriber_id" : "123"
},
"count" : 2
}
Von den „drei“ Dokumenten in der Stichprobe gehören also „2“ zu einem eindeutigen Wert und „1“ zu einem anderen. Dies kann immer noch mit $sum
summiert werden um die gesamten übereinstimmenden Dokumente zu erhalten, die Sie in der folgenden Phase ausführen, mit dem Endergebnis:
{
"_id" : {
"campaign_id" : "A",
"campaign_name" : "A"
},
"totalCount" : 3,
"distinctCount" : 2
}
Eine wirklich gute Analogie für die Aggregationspipeline ist die Unix-Pipe „|“ -Operator, der eine "Verkettung" von Operationen ermöglicht, sodass Sie die Ausgabe eines Befehls an die Eingabe des nächsten übergeben können und so weiter. Wenn Sie beginnen, Ihre Verarbeitungsanforderungen auf diese Weise zu betrachten, können Sie die Vorgänge mit der Aggregationspipeline besser verstehen.