2012-01-07 21 views
7

En MySQLgrupo MongoDB por Funcionalidades

select a,b,count(1) as cnt from list group by a, b having cnt > 2; 

I tiene que ejecutar el grupo de función usando tener condición en mongodb. Pero recibo el siguiente error. Por favor comparte tu opinión.

En MongoDB

> res = db.list.group({key:{a:true,b:true}, 
...      reduce: function(obj,prev) {prev.count++;}, 
...      initial: {count:0}}).limit(10); 

Sat Jan 7 16:36:30 uncaught exception: group command failed: { 
     "errmsg" : "exception: group() can't handle more than 20000 unique keys", 
     "code" : 10043, 
     "ok" : 0 

Una vez que se va a ejecutar, tenemos que ejecutar el siguiente archivo en el próximo.

for (i in res) {if (res[i].count>2) printjson(res[i])}; 

Saludos, kumaran

Respuesta

12

MongoDB group by es muy limitado en la mayoría de los casos, por ejemplo

- the result set must be lesser than 10000 keys. 
- it will not work in sharded environments 

Así que es mejor usar MapReduce. por lo que la consulta sería así

map = function() {emit ({a: true, b: true}, {count: 1}); }

reduce = function(k, values) { 
    var result = {count: 0}; 
    values.forEach(function(value) { 
     result.count += value.count; 
    }); 
    return result; 
} 

y luego

db.list.mapReduce(map,reduce,{out: { inline : 1}}) 

Es una versión no probado. quiero saber si funciona

EDIT:

La función de mapa anterior era defectuoso. Por eso no estás obteniendo los resultados.que debería haber sido

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

datos de prueba:

> db.multi_group.insert({a:1,b:2}) 
> db.multi_group.insert({a:2,b:2}) 
> db.multi_group.insert({a:3,b:2}) 
> db.multi_group.insert({a:1,b:2}) 
> db.multi_group.insert({a:3,b:2}) 
> db.multi_group.insert({a:7,b:2}) 


> db.multi_group.mapReduce(map,reduce,{out: { inline : 1}}) 
{ 
    "results" : [ 
     { 
      "_id" : { 
       "a" : 1, 
       "b" : 2 
      }, 
      "value" : { 
       "count" : 2 
      } 
     }, 
     { 
      "_id" : { 
       "a" : 2, 
       "b" : 2 
      }, 
      "value" : { 
       "count" : 1 
      } 
     }, 
     { 
      "_id" : { 
       "a" : 3, 
       "b" : 2 
      }, 
      "value" : { 
       "count" : 2 
      } 
     }, 
     { 
      "_id" : { 
       "a" : 7, 
       "b" : 2 
      }, 
      "value" : { 
       "count" : 1 
      } 
     } 
    ], 
    "timeMillis" : 1, 
    "counts" : { 
     "input" : 6, 
     "emit" : 6, 
     "reduce" : 2, 
     "output" : 4 
    }, 
    "ok" : 1, 
} 

Edit2:

solución completa que incluye la aplicación de tener contador> = 2

map = function() { 
    emit({a:this.a, b:this.b}, {count:1,_id:this._id}); 
} 

reduce = function(k, values) { 
    var result = {count: 0,_id:[]}; 
    values.forEach(function(value) { 
     result.count += value.count; 
     result._id.push(value._id); 
    }); 
    return result; 
} 

>db.multi_group.mapReduce(map,reduce,{out: { replace : "multi_result"}}) 

> db.multi_result.find({'value.count' : {$gte : 2}}) 
{ "_id" : { "a" : 1, "b" : 2 }, "value" : { "_id" : [ ObjectId("4f0adf2884025491024f994c"), ObjectId("4f0adf3284025491024f994f") ], "count" : 2 } } 
{ "_id" : { "a" : 3, "b" : 2 }, "value" : { "_id" : [ ObjectId("4f0adf3084025491024f994e"), ObjectId("4f0adf3584025491024f9950") ], "count" : 2 } } 
+0

comprobé, pero no devuelve el resultado correcto. fue el recuento total de la colección. En realidad, lo que estoy esperando significa, quiero saber cuántas entradas duplicadas se encuentran en esta colección con la combinación de un valor de a & b – Kumaran

+0

@Kumaran, hay un error en la función de mi mapa. he actualizado la nueva función. eso funcionará ... verifíquelo – RameshVel

+0

@Kumaran, verifique la edición final. eso es el equivalente de sql group por y tener el uso de mapreduce. – RameshVel

0

Debe utilizar MapReduce lugar. El grupo tiene sus limitaciones.

En el futuro, podrá utilizar el Aggregation Framework. Pero por ahora, usa map/reduce.

0

Depende de la número ero de los grupos, se podría encontrar una solución más simple y más rápido que grupo o MapReduce utilizando distinta:

var res = []; 
for(var cur_a = db.list.distinct('a'); cur_a.hasNext();) { 
    var a = cur_a.next(); 
    for(var cur_b = db.list.distinct('b'); cur_b.hasNext();) { 
    var b = cur_b.next(); 
    var cnt = db.list.count({'a':a,'b':b}) 
    if (cnt > 2) 
     res.push({ 'a': a, 'b' : b 'cnt': cnt} 
    } 
} 

que será más rápido si tiene índices de a y b

db.list.ensureIndex({'a':1,'b':1})