MongoDB select count (distinct x) на индексированном столбце-подсчет уникальных результатов для больших наборов данных
Я прошел через несколько статей и примеров, и еще не нашел эффективного способа сделать этот 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
например
- это как сделать distinct и group в mongodb? (не принято, ответ автора / OP не проверял его)
- это одна группа MongoDB по функциональным возможностям (похоже на вторую попытку)
- этот 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
Update2:
кажется, что новая структура агрегации отвечает на вышеприведенный комментарий... (MongoDB 2.1 / 2.2 и выше, предварительный просмотр разработки доступен, а не для производства)
1 ответ:
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) Если вы хотите сделать это с карте/уменьшить можно. Это двухэтапный процесс: на первом этапе мы строим новую коллекцию со списком каждого уникального значения ключа. Во втором мы делаем подсчет () на новую коллекцию.
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() );
обратите внимание, что вы не можете вернуть результат map / reduce inline, потому что это потенциально превысит ограничение на размер документа 16 МБ. Ты можете сохраните расчет в коллекции, а затем подсчитайте() размер коллекции, или вы можете получить количество результатов из возвращаемого значения mapReduce().