mongodb conta num di valori distinti per campo / chiave


104

Esiste una query per calcolare quanti valori distinti contiene un campo nel DB.

es. ho un campo per paese e ci sono 8 tipi di valori per paese (spagna, inghilterra, francia, ecc ...)

Se qualcuno aggiunge più documenti con un nuovo paese, vorrei che la query restituisse 9.

C'è un modo più semplice per raggruppare e contare?


2
Hai esaminato il framework di aggregazione ?
WiredPrairie


Risposte:


198

MongoDB ha un distinctcomando che restituisce un array di valori distinti per un campo; puoi controllare la lunghezza della matrice per un conteggio.

C'è anche un db.collection.distinct()helper della shell :

> db.countries.distinct('country');
[ "Spain", "England", "France", "Australia" ]

> db.countries.distinct('country').length
4

47
questo non funziona davvero se il tuo numero di valori distinti è troppo alto ... se stavi guardando nomi distinti di persone nel mondo o qualcosa del genere. hai una risposta che scala?
underrun

3
1+ per la lunghezza. stavo lottando per trovare qualcosa del genere. Grazie.
Adeel Ahmad

Non so perché non usano count () anche lì
Marian Klühspies

1
@ MarianKlühspies - perché è solo un array javascript, che utilizza la proprietà length per contare il numero di elementi.
UpTheCreek

Proprio quello che stavo cercando ... TY
Maulzey

113

Ecco un esempio di utilizzo dell'API di aggregazione. Per complicare il caso, stiamo raggruppando per parole senza distinzione tra maiuscole e minuscole dalla proprietà array del documento.

db.articles.aggregate([
    {
        $match: {
            keywords: { $not: {$size: 0} }
        }
    },
    { $unwind: "$keywords" },
    {
        $group: {
            _id: {$toLower: '$keywords'},
            count: { $sum: 1 }
        }
    },
    {
        $match: {
            count: { $gte: 2 }
        }
    },
    { $sort : { count : -1} },
    { $limit : 100 }
]);

che danno risultati come

{ "_id" : "inflammation", "count" : 765 }
{ "_id" : "obesity", "count" : 641 }
{ "_id" : "epidemiology", "count" : 617 }
{ "_id" : "cancer", "count" : 604 }
{ "_id" : "breast cancer", "count" : 596 }
{ "_id" : "apoptosis", "count" : 570 }
{ "_id" : "children", "count" : 487 }
{ "_id" : "depression", "count" : 474 }
{ "_id" : "hiv", "count" : 468 }
{ "_id" : "prognosis", "count" : 428 }

2
Accesso solo per + questa risposta. Grazie! btw se lo stai facendo su un campo unico, rimuovi semplicemente la linea di svolgimento.
Richie Rich

@RichieRich, unwindè necessario perché il codice raggruppa valori individuali di un campo array che corrisponde a come distinctfunziona.
Paul

@ Paul quello che ha detto Richie è che se il raggruppamento viene eseguito solo sul campo "normale" (stringa, int, ecc.), Non è necessario il passaggio di svolgimento. Non è corretto?
guyarad

@guyarad unwindè necessario quando si lavora con gli array.
Paul

+1 per la risposta, esattamente la cosa su cui stavo lavorando, per quanto distinta ha il suo fascino ma questo è solo oro :) - comunque devo leggere di più sugli aggregati per ottenere il set di risultati desiderato per filtrare i dati
Talha

21

Con MongoDb 3.4.4 e versioni successive, puoi sfruttare l'uso $arrayToObjectdell'operatore e di una $replaceRootpipeline per ottenere i conteggi.

Ad esempio, supponiamo di avere una raccolta di utenti con ruoli diversi e di voler calcolare i conteggi distinti dei ruoli. Dovresti eseguire la seguente pipeline aggregata:

db.users.aggregate([
    { "$group": {
        "_id": { "$toLower": "$role" },
        "count": { "$sum": 1 }
    } },
    { "$group": {
        "_id": null,
        "counts": {
            "$push": { "k": "$_id", "v": "$count" }
        }
    } },
    { "$replaceRoot": {
        "newRoot": { "$arrayToObject": "$counts" }
    } }    
])

Output di esempio

{
    "user" : 67,
    "superuser" : 5,
    "admin" : 4,
    "moderator" : 12
}

Questa non è la risposta alla domanda, ma è comunque utile. Mi chiedo come si comporta rispetto a .distinct().
Redsandro

9

Puoi sfruttare le estensioni di Mongo Shell . È una singola importazione .js che puoi aggiungere al tuo $HOME/.mongorc.js, o in modo programmatico, se stai codificando anche in Node.js / io.js.

Campione

Per ogni valore distinto di campo conta le occorrenze nei documenti facoltativamente filtrati per query

> db.users.distinctAndCount('name', {name: /^a/i})

{
  "Abagail": 1,
  "Abbey": 3,
  "Abbie": 1,
  ...
}

Il parametro field potrebbe essere un array di campi

> db.users.distinctAndCount(['name','job'], {name: /^a/i})

{
  "Austin,Educator" : 1,
  "Aurelia,Educator" : 1,
  "Augustine,Carpenter" : 1,
  ...
}

come lo importerei nel nodo?
Salmaan P

require("./script.js"), suppongo
evandrix

giusto, ma non sono riuscito a ottenere le funzioni all'interno. Come li uso. Sono definiti come db.protoptype.distinctAndCount
Salmaan P

C'è una sezione di istruzioni nel file readme del repo (RTFM! 1 !! 1!) Fondamentalmente, metti il .mongorc.jsfile nella tua directory home. Fatto.
Janis F

6

Per trovare distinti nella field_1raccolta, ma vogliamo anche alcune WHEREcondizioni di quelle che possiamo fare come segue:

db.your_collection_name.distinct('field_1', {WHERE condition here and it should return a document})

Quindi, trova un numero distinto namesda una raccolta in cui l'età> 25 sarà come:

db.your_collection_name.distinct('names', {'age': {"$gt": 25}})

Spero che sia d'aiuto!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.