He revisado varios artículos y ejemplos, y todavía tengo que encontrar una forma eficiente de hacer esta consulta SQL en MongoDB (donde hay millones de filas documentos)
Primer intento
(por ejemplo, de esta pregunta casi duplicada: ¿ equivalente de Mongo de SELECT DISTINCT de SQL? )
db.myCollection.distinct("myIndexedNonUniqueField").length
Obviamente recibí este error porque mi conjunto de datos es enorme
Thu Aug 02 12:55:24 uncaught exception: distinct failed: {
"errmsg" : "exception: distinct too big, 16mb cap",
"code" : 10044,
"ok" : 0
}
Segundo intento
Decidí intentar hacer un grupo
db.myCollection.group({key: {myIndexedNonUniqueField: 1},
initial: {count: 0},
reduce: function (obj, prev) { prev.count++;} } );
Pero recibí este mensaje de error en su lugar:
exception: group() can't handle more than 20000 unique keys
Tercer intento
No lo he probado todavía, pero hay varias sugerencias que implican mapReduce
p.ej
- este cómo hacer distintos y grupos en mongodb? (no aceptado, el autor de la respuesta / OP no lo probó)
- este grupo MongoDB por funcionalidades (parece similar al segundo intento)
- este http://blog.emmettshear.com/post/2010/02/12/Counting-Uniques-With-MongoDB
- este https://groups.google.com/forum/?fromgroups#!topic/mongodb-user/trDn3jJjqtE
- este http://cookbook.mongodb.org/patterns/unique_items_map_reduce/
también
Parece que hay una solicitud de extracción en GitHub que corrige el .distinct
método para mencionar que solo debería devolver un recuento, pero aún está abierto: https://github.com/mongodb/mongo/pull/34
Pero en este punto pensé que vale la pena preguntar aquí, ¿qué es lo último sobre el tema? ¿Debo pasar a SQL u otra base de datos NoSQL para distintos recuentos? o hay una forma eficiente?
Actualizar:
Este comentario sobre los documentos oficiales de MongoDB no es alentador, ¿es cierto?
http://www.mongodb.org/display/DOCS/Aggregation#comment-430445808
Actualización2:
Parece que el nuevo Aggregation Framework responde al comentario anterior ... (MongoDB 2.1 / 2.2 y superior, vista previa de desarrollo disponible, no para producción)
Respuestas:
1) La forma más sencilla de hacerlo es a través del marco de agregación. Esto requiere dos comandos "$ group": el primero agrupa por valores distintos, el segundo cuenta todos los valores distintos
pipeline = [ { $group: { _id: "$myIndexedNonUniqueField"} }, { $group: { _id: 1, count: { $sum: 1 } } } ]; // // Run the aggregation command // R = db.runCommand( { "aggregate": "myCollection" , "pipeline": pipeline } ); printjson(R);
2) Si desea hacer esto con Map / Reduce, puede hacerlo. Este también es un proceso de dos fases: en la primera fase creamos una nueva colección con una lista de cada valor distinto para la clave. En el segundo hacemos un recuento () de la nueva colección.
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() );
Tenga en cuenta que no puede devolver el resultado del mapa / reducir en línea, porque eso potencialmente sobrepasará el límite de tamaño del documento de 16 MB. Usted puede ahorrar el cálculo de una colección y luego contar () el tamaño de la colección, o puede obtener el número de resultados a partir del valor de retorno de MapReduce ().
fuente
$group
declaración antes de ser devueltos a mongos?db.myCollection.aggregate( {$group : {_id : "$myIndexedNonUniqueField"} }, {$group: {_id:1, count: {$sum : 1 }}});
directo al resultado:
db.myCollection.aggregate( {$group : {_id : "$myIndexedNonUniqueField"} }, {$group: {_id:1, count: {$sum : 1 }}}) .result[0].count;
fuente
La siguiente solución funcionó para mí
fuente