1

我有一个集合,其中的文档结构如下:

{
  responses: {
    key1: bar,
    key2: quux
    ...
  },...
}

有没有办法获取responses对象中每个唯一键、值对的计数?例如,我希望看到如下结果(确切的结构无关紧要):

{
  key1: {
    foo: 7 // aka 7 objects are similar to { responses: [{key: foo}] }
    bar: 30
  },
  key2: {
    baz: 24,
    quux: 13
  }
}
4

2 回答 2

2

有几种方法可以做到这一点。聚合框架还不能做到这一点,因为您无法将键名映射到值。但是 map reduce 让它变得相对简单:

map = function () { 
       for (k in this.responses) { 
          emit( { key: k, response: this.responses[k]}, 1 ); 
       } 
}

reduce = function (k, values) { 
       result = 0;  
       values.forEach( function(v) { result += v; } ); 
       return result; 
}

在此示例数据集上:

> db.responses.find({},{_id:0,responses:1}).pretty()
{ "responses" : { "key1" : "foo", "key2" : "bar" } }
{ "responses" : { "key1" : "foo", "key3" : "bar" } }
{ "responses" : { "key2" : "foo", "key3" : "bar" } }
{ "responses" : { "key3" : "baz" } }

运行 MR 让您:

> db.responses.mapReduce(map, reduce, {out:{inline:1}})
{
    "results" : [
        {
            "_id" : {
                "key" : "key1",
                "response" : "foo"
            },
            "value" : 2
        },
        {
            "_id" : {
                "key" : "key2",
                "response" : "bar"
            },
            "value" : 1
        },
        {
            "_id" : {
                "key" : "key2",
                "response" : "foo"
            },
            "value" : 1
        },
        {
            "_id" : {
                "key" : "key3",
                "response" : "bar"
            },
            "value" : 2
        },
        {
            "_id" : {
                "key" : "key3",
                "response" : "baz"
            },
            "value" : 1
        }
    ],
    "timeMillis" : 65,
    "counts" : {
        "input" : 4,
        "emit" : 7,
        "reduce" : 2,
        "output" : 5
    },
    "ok" : 1,
}

这是通过 mapreduce 执行此操作的第二种方法-这使输出更像您所说的要查找的内容:

m2 = function () {
    for (k in this.responses) {
      keyname = this.responses[k];
      val = {};
      val[keyname] = 1;
      emit ( k, val );
    }
}
r2 = function (k, values) {
      result = { };
      values.forEach ( function(v) {
          for (k in v) {
             if (result[k] > 0) {
                result[k] += v[k];
             } else {
                result[k] = v[k];
             }
          }
      } );
      return result;
}

结果是:

> db.responses.mapReduce(m2, r2, {out:{inline:1}})
{
    "results" : [
        {
            "_id" : "key1",
            "value" : {
                "foo" : 2
            }
        },
        {
            "_id" : "key2",
            "value" : {
                "bar" : 1,
                "foo" : 1
            }
        },
        {
            "_id" : "key3",
            "value" : {
                "bar" : 2,
                "baz" : 1
            }
        }
    ],
    "timeMillis" : 3,
    "counts" : {
        "input" : 4,
        "emit" : 7,
        "reduce" : 3,
        "output" : 3
    },
    "ok" : 1,
}
于 2013-05-11T21:09:09.003 回答
1

这可以通过 map reduce 来实现。你会发现你想用你的 map 函数计算的所有键,并在你的 reduce 函数中将发出的结果减少到一个计数中。

这是一个很好的关于mongodb中map reduce的视频解释,你以前没用过……

http://www.youtube.com/watch?v=WovfjprPD_I

于 2013-05-11T02:07:06.987 回答