2012-11-23 18 views
24

Supponendo che ho una collezione chiamata "post" (in realtà si tratta di una collezione più complessa, i messaggi è troppo semplice) con la seguente struttura:

> db.posts.find() 

{ "id" : ObjectId("50ad8d451d41c8fc58000003"), "title" : "Lorem ipsum", "author" : 
"John Doe", "content" : "This is the content", "tags" : [ "SOME", "RANDOM", "TAGS" ] } 

mi aspetto questa collezione per coprire centinaia di migliaia, forse milioni, che ho bisogno di interrogare per post per tag e raggruppare i risultati per tag e visualizzare i risultati impaginati. Questo è dove il quadro di aggregazione viene in Ho intenzione di utilizzare il metodo di aggregazione() per interrogare la collezione:.

db.posts.aggregate(
    { "unwind" : "$tags" }, 
    { "group" : { 
     _id: { tag: "$tags" }, 
     count: { $sum: 1 } 
    } } 
); 

Il problema è che per creare il Paginator avrei bisogno di conoscere la lunghezza della matrice di uscita. So che per fare che si può fare:

db.posts.aggregate(
    { "unwind" : "$tags" }, 
    { "group" : { 
     _id: { tag: "$tags" }, 
     count: { $sum: 1 } 
    } } 
    { "group" : { 
     _id: null, 
     total: { $sum: 1 } 
    } } 
); 

ma che sarebbe scartare l'uscita dalla tubazione precedente (il primo gruppo). Esiste un modo per combinare le due operazioni preservando l'output di ciascuna pipeline? So che l'output dell'intera operazione di aggregazione può essere convertito in un array in una lingua e il conteggio dei contenuti, ma potrebbe esserci la possibilità che l'output della pipeline possa superare il limite di 16 Mb. Inoltre, eseguire la stessa query solo per ottenere il conteggio sembra uno spreco.

Quindi è possibile ottenere il risultato del documento e contare allo stesso tempo? Qualsiasi aiuto è apprezzato.

+2

Avete davvero bisogno di un conteggio totale completamente accurato, o se un'approssimazione fare? Poi di nuovo, sembra che tu stia contando tutti i post quindi non è solo un'operazione di conteggio() che puoi fare? – cirrus

+0

In realtà sto facendo un conteggio su un gruppo di post così count() non lo farà. – MervS

+0

soluzione perfetta per ottenere il totale preservando il risultato in pipe di aggregazione http://stackoverflow.com/a/39784851/3666966 –

risposta

30
  1. Usa $project per salvare tag e count in tmp
  2. Utilizzare $push o addToSet per memorizzare tmp nell'elenco data.

Codice:

db.test.aggregate(
    {$unwind: '$tags'}, 
    {$group:{_id: '$tags', count:{$sum:1}}}, 
    {$project:{tmp:{tag:'$_id', count:'$count'}}}, 
    {$group:{_id:null, total:{$sum:1}, data:{$addToSet:'$tmp'}}} 
) 

uscita:

{ 
    "result" : [ 
      { 
        "_id" : null, 
        "total" : 5, 
        "data" : [ 
          { 
            "tag" : "SOME", 
            "count" : 1 
          }, 
          { 
            "tag" : "RANDOM", 
            "count" : 2 
          }, 
          { 
            "tag" : "TAGS1", 
            "count" : 1 
          }, 
          { 
            "tag" : "TAGS", 
            "count" : 1 
          }, 
          { 
            "tag" : "SOME1", 
            "count" : 1 
          } 
         ] 
       } 
     ], 
     "ok" : 1 
} 
+0

Non sono a conoscenza del fatto che è possibile includere più campi in un nuovo campo nella pipeline '$ project'. Questo è esattamente ciò di cui ho bisogno. Grazie. – MervS

+1

E 'possibile ordinare $, saltare o $ limitare i dati usando questo metodo? Non puoi limitare i dati prima di $ project, e non vedo un modo per farlo dopo senza perdere il 'totale'. Inoltre, {$ sort: {'data.count': 1}} non sembra funzionare come di solito avviene nelle query non aggregate. –

3

Non sono sicuro che è necessario il quadro di aggregazione per questo altro che contare tutti i tag ad esempio:

db.posts.aggregate(
    { "unwind" : "$tags" }, 
    { "group" : { 
     _id: { tag: "$tags" }, 
     count: { $sum: 1 } 
    } } 
); 

Per impaginare attraverso ogni tag si può semplicemente utilizzare la normale sintassi di query - in questo modo:

db.posts.find({tags: "RANDOM"}).skip(10).limit(10) 
+0

Che funzionerebbe se sto cercando tutti i post con il tag "RANDOM" ma in realtà sto raggruppando i post dai loro tag e il gruppo risultante è ciò che richiede il paging. – MervS

+0

Ah, non ne ero sicuro! – Ross

Problemi correlati