Frage MongoDB select count (distinct x) für eine indizierte Spalte - zähle eindeutige Ergebnisse für große Datensätze


Ich habe mehrere Artikel und Beispiele durchgelesen und muss noch eine effiziente Möglichkeit finden, diese SQL - Abfrage in MongoDB (wo es Millionen von Reihen Unterlagen)

Erster Versuch 

(z. B. aus dieser fast doppelten Frage - Mongo Äquivalent von SQL SELECT DISTINCT?)

db.myCollection.distinct("myIndexedNonUniqueField").length

Offensichtlich habe ich diesen Fehler bekommen, da mein Datensatz sehr groß ist

Thu Aug 02 12:55:24 uncaught exception: distinct failed: {
        "errmsg" : "exception: distinct too big, 16mb cap",
        "code" : 10044,
        "ok" : 0
}

Zweiter Versuch

Ich beschloss, eine Gruppe zu machen

db.myCollection.group({key: {myIndexedNonUniqueField: 1},
                initial: {count: 0}, 
                 reduce: function (obj, prev) { prev.count++;} } );

Aber ich habe stattdessen diese Fehlermeldung erhalten:

exception: group() can't handle more than 20000 unique keys

Dritter Versuch 

Ich habe es noch nicht versucht, aber es gibt mehrere Vorschläge, die dazu gehören mapReduce

z.B.

Ebenfalls

Es scheint, dass es eine Pull-Anfrage auf GitHub gibt, die das repariert .distinct Methode, um es zu erwähnen, sollte nur eine Zählung zurückgeben, aber es ist immer noch offen: https://github.com/mongodb/mongo/pull/34

Aber zu diesem Zeitpunkt dachte ich, es lohnt sich, hier nach dem neuesten Stand zu fragen. Soll ich für unterschiedliche Zählungen zu SQL oder einer anderen NoSQL-Datenbank wechseln? oder gibt es einen effizienten weg?

Aktualisieren: 

Dieser Kommentar zu den offiziellen MongoDB-Dokumenten ist nicht ermutigend, ist das korrekt?

http://www.mongodb.org/display/DOCS/Aggregation#comment-430445808

Update2:

Scheint, dass das neue Aggregations-Framework den obigen Kommentar beantwortet ... (MongoDB 2.1 / 2.2 und höher, Entwicklungsvorschau verfügbar, nicht für Produktion)

http://docs.mongodb.org/manual/applications/aggregation/


76
2017-08-02 17:17


Ursprung


Antworten:


1) Der einfachste Weg dazu ist über das Aggregations-Framework. Dies erfordert zwei "$ group" -Befehle: der erste gruppiert nach bestimmten Werten, der zweite zählt alle unterschiedlichen Werte

pipeline = [ 
    { $group: { _id: "$myIndexedNonUniqueField"}  },
    { $group: { _id: 1, count: { $sum: 1 } } }
];

//
// Run the aggregation command
//
R = db.runCommand( 
    {
    "aggregate": "myCollection" , 
    "pipeline": pipeline
    }
);
printjson(R);

2) Wenn Sie dies mit Map / Reduce tun möchten, können Sie. Dies ist auch ein zweiphasiger Prozess: In der ersten Phase erstellen wir eine neue Sammlung mit einer Liste aller unterschiedlichen Werte für den Schlüssel. In der zweiten machen wir einen Count () für die neue Kollektion.

var SOURCE = db.myCollection;
var DEST = db.distinct
DEST.drop();


map = function() {
  emit( this.myIndexedNonUniqueField , {count: 1});
}

reduce = function(key, values) {
  var count = 0;

  values.forEach(function(v) {
    count += v['count'];        // count each distinct value for lagniappe
  });

  return {count: count};
};

//
// run map/reduce
//
res = SOURCE.mapReduce( map, reduce, 
    { out: 'distinct', 
     verbose: true
    }
    );

print( "distinct count= " + res.counts.output );
print( "distinct count=", DEST.count() );

Beachten Sie, dass Sie das Ergebnis von map / reduce inline nicht zurückgeben können, da dies möglicherweise die maximale Größe von 16 MB überschreitet. Sie kann Speichern Sie die Berechnung in einer Auflistung und zählen Sie dann () die Größe der Auflistung, oder Sie können die Anzahl der Ergebnisse aus dem Rückgabewert von mapReduce () abrufen.


68
2017-08-02 22:39



db.myCollection.aggregate( 
   {$group : {_id : "$myIndexedNonUniqueField"} }, 
   {$group: {_id:1, count: {$sum : 1 }}});

direkt zum Ergebnis:

db.myCollection.aggregate( 
   {$group : {_id : "$myIndexedNonUniqueField"} }, 
   {$group: {_id:1, count: {$sum : 1 }}})
   .result[0].count;

37
2018-03-04 21:32



Die folgende Lösung hat für mich funktioniert

db.test.distinct ('Benutzer');   ["alex", "England", "Frankreich", "Australien"]

db.countries.distinct ('Land'). Länge   4


3
2018-05-25 06:06