6

MySQL では

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

mongodb の有条件を使用して、関数ごとにグループを実行する必要があります。しかし、次のエラーが発生します。あなたの意見を共有してください。

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

実行されると、次のファイルを実行する必要があります。

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

よろしく、クマラン

4

3 に答える 3

13

たとえば、 MongoDB group byは、ほとんどの場合非常に制限されています。

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

したがって、mapreduceを使用することをお勧めします。したがって、クエリは次のようになります

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

その後

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

その未テストのバージョン。それが機能するかどうか私に知らせてください

編集:

以前のマップ機能に欠陥がありました。そのため、結果が得られません。あるべきだった

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

テストデータ:

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

カウント>=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 } }
于 2012-01-07T13:32:07.603 に答える
0

代わりにMapReduceを使用する必要があります。グループには限界があります。

将来的にはAggregation Frameworkを使用できるようになります。しかし今のところ、map/reduce を使用してください。

于 2012-01-07T11:33:06.990 に答える
0

グループの数によっては、 distinctを使用することで、 groupMapReduceよりも簡単で高速なソリューションが見つかる場合があります。

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

a と b にインデックスがあると高速になります

db.list.ensureIndex({'a':1,'b':1})
于 2012-04-20T20:45:00.787 に答える