2012-01-07 30 views
7

Trong MySQLMongoDB nhóm bởi Các chức năng

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

tôi phải thực hiện nhóm bằng cách sử dụng chức năng có điều kiện trong MongoDB. Nhưng tôi nhận được lỗi sau. Xin vui lòng chia sẻ đầu vào của bạn.

Trong 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 

Một khi nó sẽ được thực hiện, chúng ta cần để chạy các tập tin sau đây về sau.

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

Kính trọng, Kumaran

Trả lời

12

MongoDB group by là rất hạn chế trong hầu hết các trường hợp, ví dụ

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

Vì vậy, nó tốt hơn để sử dụng MapReduce. do đó truy vấn sẽ như thế này

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

và sau đó

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

của một phiên bản chưa được kiểm tra. cho tôi biết nếu nó hoạt động

EDIT:

Chức năng bản đồ trước đó đã bị lỗi. Đó là lý do tại sao bạn không nhận được kết quả.nó cần phải có được

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

Test data:

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

Hoàn thành giải pháp trong đó có việc áp dụng có số lượng> = 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

tôi đã kiểm tra, nhưng nó không trả lại kết quả chính xác. nó đã trả về tổng số bộ sưu tập. Trên thực tế những gì tôi mong đợi có nghĩa là, tôi muốn biết có bao nhiêu mục trùng lặp được tìm thấy trong bộ sưu tập này với sự kết hợp a & b giá trị – Kumaran

+0

@Kumaran, có một lỗi trong chức năng bản đồ của tôi. tôi đã cập nhật chức năng mới. mà sẽ làm việc .. kiểm tra xem nó – RameshVel

+0

@Kumaran, kiểm tra chỉnh sửa cuối cùng. thats tương đương với nhóm sql bởi và có sử dụng mapreduce. – RameshVel

0

Bạn nên sử dụng MapReduce để thay thế. Tập đoàn có những hạn chế của nó.

Trong tương lai, bạn sẽ có thể sử dụng Aggregation Framework. Nhưng hiện tại, hãy sử dụng bản đồ/giảm.

0

Phụ thuộc vào số ber các nhóm của bạn, bạn có thể tìm thấy một giải pháp đơn giản và nhanh hơn nhóm hoặc MapReduce bằng cách sử dụng biệt:

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

Nó sẽ nhanh hơn nếu bạn có chỉ số trên a và b

db.list.ensureIndex({'a':1,'b':1}) 
Các vấn đề liên quan