Я просмотрел несколько статей и примеров, но еще не нашел эффективного способа выполнить этот SQL-запрос в MongoDB (где есть миллионы ряды документы)
Первая попытка
(например, из этого почти повторяющегося вопроса - монго-эквивалент SQL SELECT DISTINCT? )
db.myCollection.distinct("myIndexedNonUniqueField").length
Очевидно, я получил эту ошибку, так как мой набор данных огромен
Thu Aug 02 12:55:24 uncaught exception: distinct failed: {
"errmsg" : "exception: distinct too big, 16mb cap",
"code" : 10044,
"ok" : 0
}
Вторая попытка
Я решил попробовать сделать группу
db.myCollection.group({key: {myIndexedNonUniqueField: 1},
initial: {count: 0},
reduce: function (obj, prev) { prev.count++;} } );
Но вместо этого я получил это сообщение об ошибке:
exception: group() can't handle more than 20000 unique keys
Третья попытка
Я еще не пробовал, но есть несколько предложений, касающихся mapReduce
например
- этот как сделать отдельный и сгруппировать в mongodb? (не принято, автор ответа / ОП не проверял)
- эта одна группа MongoDB по функциям (похоже на Second Attempt)
- это http://blog.emmettshear.com/post/2010/02/12/Counting-Uniques-With-MongoDB
- этот https://groups.google.com/forum/?fromgroups#!topic/mongodb-user/trDn3jJjqtE
- это http://cookbook.mongodb.org/patterns/unique_items_map_reduce/
Также
Кажется, есть запрос на перенос на GitHub, исправляющий .distinct
метод, чтобы упомянуть, что он должен возвращать только счетчик, но он все еще открыт: https://github.com/mongodb/mongo/pull/34
Но в этот момент я подумал, что стоит спросить здесь, что нового по этой теме? Должен ли я перейти на SQL или другую базу данных NoSQL для различных подсчетов? или есть эффективный способ?
Обновить:
Этот комментарий к официальным документам MongoDB не обнадеживает, это точно?
http://www.mongodb.org/display/DOCS/Aggregation#comment-430445808
Обновление2:
Кажется, новая структура агрегирования отвечает на приведенный выше комментарий ... (MongoDB 2.1 / 2.2 и выше, доступна предварительная версия для разработки, не для производства)
Ответы:
1) Самый простой способ сделать это - использовать фреймворк агрегации. Для этого нужны две команды «$ group»: первая группирует по отдельным значениям, вторая подсчитывает все отдельные значения.
pipeline = [ { $group: { _id: "$myIndexedNonUniqueField"} }, { $group: { _id: 1, count: { $sum: 1 } } } ]; // // Run the aggregation command // R = db.runCommand( { "aggregate": "myCollection" , "pipeline": pipeline } ); printjson(R);
2) Если вы хотите сделать это с помощью Map / Reduce, вы можете. Это также двухэтапный процесс: на первом этапе мы создаем новую коллекцию со списком всех отдельных значений ключа. Во втором мы делаем count () для новой коллекции.
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() );
Обратите внимание, что вы не можете вернуть результат встроенной карты / уменьшения, потому что это потенциально может превысить ограничение на размер документа 16 МБ. Вы можете сохранить вычисление в коллекции, а затем count () размер коллекции или вы можете получить количество результатов из возвращаемого значения mapReduce ().
источник
$group
операторе перед передачей обратно в mongos?db.myCollection.aggregate( {$group : {_id : "$myIndexedNonUniqueField"} }, {$group: {_id:1, count: {$sum : 1 }}});
прямо к результату:
db.myCollection.aggregate( {$group : {_id : "$myIndexedNonUniqueField"} }, {$group: {_id:1, count: {$sum : 1 }}}) .result[0].count;
источник
Следующее решение сработало для меня
источник