mongodb count Anzahl unterschiedlicher Werte pro Feld / Schlüssel

104

Gibt es eine Abfrage zum Berechnen, wie viele unterschiedliche Werte ein Feld in der Datenbank enthält?

zB Ich habe ein Feld für Land und es gibt 8 Arten von Länderwerten (Spanien, England, Frankreich usw.)

Wenn jemand mehr Dokumente mit einem neuen Land hinzufügt, möchte ich, dass die Abfrage 9 zurückgibt.

Gibt es einen einfacheren Weg als gruppieren und zählen?

Liatz
quelle
2
Haben Sie sich das Aggregations- Framework angesehen?
WiredPrairie
1
Oder kartenreduzieren ?
WiredPrairie

Antworten:

197

MongoDB verfügt über einen distinctBefehl, der ein Array unterschiedlicher Werte für ein Feld zurückgibt. Sie können die Länge des Arrays auf eine Anzahl überprüfen.

Es gibt auch einen Shell- db.collection.distinct()Helfer:

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

> db.countries.distinct('country').length
4
Stennie
quelle
46
Dies funktioniert nicht wirklich, wenn Ihre Anzahl unterschiedlicher Werte zu hoch ist ... wenn Sie sich unterschiedliche Namen von Menschen auf der Welt oder so etwas angesehen haben. Hast du eine Antwort, die skaliert?
Unterlauf
3
1+ für die Länge. Ich hatte Mühe, so etwas zu finden. Vielen Dank.
Adeel Ahmad
Ich weiß nicht, warum sie dort auch nicht count () verwenden
Marian Klühspies
1
@ MarianKlühspies - weil es nur ein Javascript-Array ist, das die Länge-Eigenschaft verwendet, um die Anzahl der Elemente zu zählen.
UpTheCreek
Genau das, wonach ich gesucht habe ... TY
Maulzey
113

Hier ist ein Beispiel für die Verwendung der Aggregations-API. Um den Fall zu verkomplizieren, gruppieren wir nach Wörtern, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird, aus der Array-Eigenschaft des Dokuments.

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

das ergeben Ergebnis wie

{ "_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 }
Experte
quelle
2
Nur für + diese Antwort angemeldet. Vielen Dank! Übrigens, wenn Sie es auf einem eindeutigen Feld tun, entfernen Sie einfach die Abwicklungslinie.
Richie Rich
@RichieRich, unwindist erforderlich, da der Code einzelne Werte eines Array-Felds gruppiert, die der Funktionsweise entsprechen distinct.
Paul
@Paul Was Richie gesagt hat ist, dass wenn der Gruppierungsvorgang nur "reguläres" Feld (String, Int usw.) ist, Sie den Abwicklungsschritt nicht benötigen. Ist es nicht richtig?
Guyarad
@guyarad unwindist erforderlich, wenn Sie mit Arrays arbeiten.
Paul
+1 für die Antwort, genau das, woran ich gearbeitet habe, obwohl es anders ist, hat seine eigenen Reize, aber das ist nur Gold :) - Jedenfalls muss ich mehr über Aggregate lesen, um die gewünschten Ergebnisse zum Filtern von Daten zu erzielen
Talha,
21

Mit MongoDb 3.4.4 und neuer können Sie die Verwendung eines $arrayToObjectOperators und einer $replaceRootPipeline nutzen, um die Anzahl zu ermitteln .

Angenommen, Sie haben eine Sammlung von Benutzern mit unterschiedlichen Rollen und möchten die unterschiedlichen Anzahlen der Rollen berechnen. Sie müssten die folgende aggregierte Pipeline ausführen:

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

Beispielausgabe

{
    "user" : 67,
    "superuser" : 5,
    "admin" : 4,
    "moderator" : 12
}
chridam
quelle
Dies ist nicht die Antwort auf die Frage, aber dennoch hilfreich. Ich frage mich, wie das im Vergleich zu funktioniert .distinct().
Redsandro
9

Sie können Mongo Shell Extensions nutzen . Es ist ein einzelner .js-Import, den Sie an Ihren $HOME/.mongorc.jsoder programmgesteuert anhängen können , wenn Sie auch in Node.js / io.js codieren.

Stichprobe

Für jeden einzelnen Wert der Feldanzahl werden die Vorkommen in Dokumenten optional nach Abfrage gefiltert

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

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

Der Feldparameter kann ein Array von Feldern sein

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

{
  "Austin,Educator" : 1,
  "Aurelia,Educator" : 1,
  "Augustine,Carpenter" : 1,
  ...
}
evandrix
quelle
Wie würde ich dies in Knoten importieren?
Salmaan P
require("./script.js")Ich nehme an
evandrix
richtig, aber ich konnte die Funktionen nicht hinein bekommen. Wie benutze ich sie? Sie sind definiert als db.protoptype.distinctAndCount
Salmaan P
Es gibt einen Abschnitt mit Anleitungen in der Readme-Datei des Repos (RTFM! 1 !! 1!). Legen Sie die .mongorc.jsDatei im Grunde genommen in Ihrem Home-Verzeichnis ab. Getan.
Janis F
6

Um field_1in der Sammlung etwas Besonderes zu finden , wollen wir aber auch eine WHEREBedingung, die wir nicht wie folgt tun können:

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

Suchen Sie also eine Nummer, die sich namesvon einer Sammlung unterscheidet, bei der das Alter> 25 wie folgt lautet:

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

Ich hoffe es hilft!

Vimal
quelle