Przejrzałem kilka artykułów i przykładów, ale nie znalazłem jeszcze efektywnego sposobu wykonania tego zapytania SQL w MongoDB (gdzie są miliony wydziwianie dokumenty)
Pierwsze podejscie
(np. z tego prawie zduplikowanego pytania - odpowiednik języka SQL SELECT DISTINCT w Mongo? )
db.myCollection.distinct("myIndexedNonUniqueField").length
Oczywiście otrzymałem ten błąd, ponieważ mój zbiór danych jest ogromny
Thu Aug 02 12:55:24 uncaught exception: distinct failed: {
"errmsg" : "exception: distinct too big, 16mb cap",
"code" : 10044,
"ok" : 0
}
Drugie podejście
Postanowiłem spróbować założyć grupę
db.myCollection.group({key: {myIndexedNonUniqueField: 1},
initial: {count: 0},
reduce: function (obj, prev) { prev.count++;} } );
Ale zamiast tego otrzymałem ten komunikat o błędzie:
exception: group() can't handle more than 20000 unique keys
Trzecia próba
Jeszcze nie próbowałem, ale jest kilka sugestii, które obejmują mapReduce
na przykład
- ten, jak zrobić odrębne i grupować w mongodb? (nie zaakceptowano, autor odpowiedzi / OP nie przetestował)
- ta jedna grupa MongoDB według funkcjonalności (wydaje się podobna do drugiej próby)
- ten http://blog.emmettshear.com/post/2010/02/12/Counting-Uniques-With-MongoDB
- ten https://groups.google.com/forum/?fromgroups#!topic/mongodb-user/trDn3jJjqtE
- ten http://cookbook.mongodb.org/patterns/unique_items_map_reduce/
Również
Wygląda na to, że na GitHubie istnieje żądanie ściągnięcia naprawiające .distinct
metodę, aby wspomnieć, że powinna ona zwracać tylko liczbę, ale nadal jest otwarta: https://github.com/mongodb/mongo/pull/34
Ale w tym miejscu pomyślałem, że warto tutaj zapytać, co jest na ten temat najnowsze? Czy powinienem przejść do SQL lub innej bazy danych NoSQL, aby uzyskać różne liczby? czy jest skuteczny sposób?
Aktualizacja:
Ten komentarz do oficjalnej dokumentacji MongoDB nie jest zachęcający, czy to prawda?
http://www.mongodb.org/display/DOCS/Aggregation#comment-430445808
Aktualizacja2:
Wygląda na to, że nowa platforma agregacji odpowiada na powyższy komentarz ... (MongoDB 2.1 / 2.2 i nowsze, dostępna wersja deweloperska, a nie produkcyjna)
Odpowiedzi:
1) Najłatwiej to zrobić za pomocą struktury agregacji. To wymaga dwóch poleceń „$ group”: pierwsza grupuje według odrębnych wartości, druga zlicza wszystkie odrębne wartości
pipeline = [ { $group: { _id: "$myIndexedNonUniqueField"} }, { $group: { _id: 1, count: { $sum: 1 } } } ]; // // Run the aggregation command // R = db.runCommand( { "aggregate": "myCollection" , "pipeline": pipeline } ); printjson(R);
2) Jeśli chcesz to zrobić za pomocą Map / Reduce, możesz. Jest to również proces dwufazowy: w pierwszej fazie tworzymy nową kolekcję z listą wszystkich odrębnych wartości klucza. W drugim liczymy () na nowej kolekcji.
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() );
Zauważ, że nie możesz zwrócić wyniku mapowania / zmniejszania w wierszu, ponieważ potencjalnie przekroczy to limit rozmiaru dokumentu 16 MB. Państwo może zapisać obliczenia w kolekcji, a następnie policzyć () wielkość zbiorów, lub można uzyskać liczbę wyników od wartości zwracanej mapreduce ().
źródło
$group
instrukcji, zanim zostaną przekazane z powrotem do mongosów?db.myCollection.aggregate( {$group : {_id : "$myIndexedNonUniqueField"} }, {$group: {_id:1, count: {$sum : 1 }}});
prosto do wyniku:
db.myCollection.aggregate( {$group : {_id : "$myIndexedNonUniqueField"} }, {$group: {_id:1, count: {$sum : 1 }}}) .result[0].count;
źródło
Poniższe rozwiązanie zadziałało dla mnie
źródło