2012-01-07 19 views
7

In MySQLgruppo MongoDB da Funzionalità

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

devo eseguire il gruppo per funzione utilizzando avendo condizione in MongoDB. Ma sto seguendo l'errore. Si prega di condividere i tuoi input.

In 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 volta che verrà eseguito, abbiamo bisogno di eseguire il seguente file sul successivo.

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

saluti, Kumaran

risposta

12

MongoDB group by è molto limitata nella maggior parte dei casi, per esempio

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

Quindi è meglio usare carta ridurre. quindi la query sarebbe come questa

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; 
} 

e poi

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

sua una versione non testata. fammi sapere se funziona

EDIT:

La funzione di mappa in precedenza era difettoso. Ecco perché non ottieni i risultati.avrebbe dovuto essere

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

dati di test:

> 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:

soluzione completa che include l'applicazione di dover count> = 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

ho controllato, ma non restituisce il risultato corretto. è stato restituito il conteggio totale della collezione. In realtà quello che mi aspetto è che voglio sapere quante voci duplicate sono state trovate in questa collezione con la combinazione a & b value – Kumaran

+0

@Kumaran, c'è un errore nella mia funzione mappa. ho aggiornato la nuova funzione. che funzionerà .. controllalo – RameshVel

+0

@Kumaran, controlla la modifica finale. questo è l'equivalente di sql group e l'uso di mapreduce. – RameshVel

0

Si dovrebbe usare MapReduce invece. Il gruppo ha i suoi limiti.

In futuro sarà possibile utilizzare Aggregation Framework. Ma per ora, usa map/reduce.

0

Dipende dal num ber i gruppi, si potrebbe trovare una soluzione più semplice e più veloce di gruppo o MapReduce utilizzando distinte:

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} 
    } 
} 

sarà più veloce se si dispone di indici su A e B

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