2014-07-15 7 views
19

che sto cercando di fare qualcosa di simileSeleziona gruppo dal conte e conteggio distinto nella query stessa MongoDB

select campaign_id,campaign_name,count(subscriber_id),count(distinct subscriber_id) 
group by campaign_id,campaign_name from campaigns; 

Questa query dando risultati, eccetto count (subscriber_id distinti)

db.campaigns.aggregate([ 
    {$match: {subscriber_id: {$ne: null}}}, 
    {$group: { 
     _id: {campaign_id: "$campaign_id",campaign_name: "$campaign_name"}, 
     count: {$sum: 1} 
    }} 
]) 

Questa seguente query dando risultati tranne count (subscriber_id)

db.campaigns_logs.aggregate([ 
    {$match : {subscriber_id: {$ne: null}}}, 
    {$group : { _id: {campaign_id: "$campaign_id",campaign_name: "$campaign_name",subscriber_id: "$subscriber_id"}}}, 
    {$group : { _id: {campaign_id: "$campaign_id",campaign_name: "$campaign_name"}, 
       count: {$sum: 1} 
       }} 
]) 

ma voglio contare (subscriber_id), conteggio (distin ct subscriber_id) nello stesso risultato

risposta

43

Stai cominciando a pensare lungo le linee giuste mentre ti dirigevi nella giusta direzione. Cambiando la tua mentalità SQL, "distinto" è in realtà solo un altro modo di scrivere un'operazione in $group in entrambe le lingue. Ciò significa che hai due operazioni di gruppo che si verificano qui e, in termini di pipeline di aggregazione, due fasi di pipeline.

Basta con i documenti semplificati di visualizzare:

{ 
    "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" 
} 

E 'ovvio che per il dato "campagna" combinazione il conteggio totale e il conteggio "distinta" sono "3" e "2", rispettivamente. Quindi la cosa logica da fare è "raggruppare" tutti quei valori "subscriber_id" e tenere il conteggio delle occorrenze per ciascuno, poi mentre pensi "pipeline", "total" quei conteggi per "campagna" e poi conta solo i " "eventi come un numero separato:

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 } 
    }} 
]) 

Dopo il primo 'distinte gruppo' documenti di output possono essere visualizzati in questo modo:

{ 
    "_id" : { 
     "campaign_id" : "A", 
     "campaign_name" : "A", 
     "subscriber_id" : "456" 
    }, 
    "count" : 1 
} 
{ 
    "_id" : { 
     "campaign_id" : "A", 
     "campaign_name" : "A", 
     "subscriber_id" : "123" 
    }, 
    "count" : 2 
} 

Così da 'tre' documenti nel campione," 2 "appartengono a un valore distinto e" 1 "a un altro. Questo può ancora essere pari con $sum al fine di ottenere i documenti di corrispondenza totale, che si fanno nella fase successiva, con il risultato finale:

{ 
    "_id" : { 
     "campaign_id" : "A", 
     "campaign_name" : "A" 
    }, 
    "totalCount" : 3, 
    "distinctCount" : 2 
} 

Un davvero buona analogia per il gasdotto di aggregazione è il tubo unix "|" operatore, che consente il "concatenamento" delle operazioni in modo da poter passare l'output di un comando fino all'input del successivo e così via. Iniziare a pensare ai requisiti di elaborazione in questo modo ti aiuterà a capire meglio le operazioni con la pipeline di aggregazione.

+0

Grazie, risposta molto utile con bella spiegazione – Rams

+1

Sì, lo Ho usato l'aggregato per un po 'e non l'ho mai capito fino ad ora. Avevo semplicemente evitato del tutto la complessità dell'aspetto dei tubi delle pipeline, perché i documenti di mongoDB sono piuttosto confusi su questo e hanno bisogno del tuo esempio! –

1

SQL Query: (gruppo da & conte di distinta)

select city,count(distinct(emailId)) from TransactionDetails group by city; 

La query Mongo equivalente sarebbe simile a questa:

db.TransactionDetails.aggregate([ 
{$group:{_id:{"CITY" : "$cityName"},uniqueCount: {$addToSet: "$emailId"}}}, 
{$project:{"CITY":1,uniqueCustomerCount:{$size:"$uniqueCount"}} } 
]);