MongoDB - 如何使用mapReduce计算多个子元素中值的频率?

时间:2014-07-23 05:28:47

标签: mongodb mapreduce

我有一个MongoDB集合,其中包含大约一百万条记录:

{
    "_id" : ObjectId("53cf413e86763c3f2e6dca36"),
    "test_data" : {
        "status" : "pass",
        "first_case" : [ 
            {
                "index" : "positionA_str",
                "name" : "test_A",
            }, 
            {
                "index" : "positionB_str",
                "name" : "test_B",
            }
        ],
        "second_case" : [ 
            {
                "index" : "positionC_str",
                "name" : "test_C",
            }, 
            {
                "index" : "positionD_str",
                "name" : "test_D",
            }
        ]
    }
}

我需要能够计算positionA_strpositionB_strpositionC_strpositionD_str的出现次数。

我做了一些研究,发现了一个简单的示例here,它向我展示了如何使用mapReduce 几乎完成此操作。

我想修改的映射函数是:

function wordMap(){

    //find words in the document text
    var word = this.text.match(/\w+/g);
    if (word == null){
        return;

    }
    for (var i = 0; i < word.length; i++){
        emit(word[i], {count: 1});
    }
}

因此,我需要修改第var word = this.text.match(/\w+/g);行来计算属于index的值。

但是,我无法找到如何做到这一点,因为它们发生在数组内部(first_case下,second_case下)。

例如,我想说的是:

var word = this.test_data.first_case[].index.match(/\w+/g);

但不允许使用[]。而且,这并不包括index second_case的任何方式。

是否有人指出如何使用mapReduce计算index的每个值的出现次数,无论其在元素结构中的子位置如何?< /强>

非常感谢任何建议!

1 个答案:

答案 0 :(得分:1)

不确定您认为您的示例与您要运行的查询有什么关系。你真正想要做的是将每个索引值“发出”为“键”,然后让“reducer”总结出现的事件:

db.collection.mapReduce(

    // mapper
    function () {

      var mkeys = ['first_case','second_case'];
      var test_data = this.test_data;

      mkeys.forEach(function(k) {
        test_data[k].forEach(function(data) {
          emit( data.index, 1 );
        });
      });
   },

   // reducer
   function(key,values) {
       return Array.sum( values );
   },
   { "out": { "inline": 1 } }
)

这真的是解决这个问题的最简单方法。只需循环每个数组并发出“index”字段值,然后“汇总”每个键上发出的1的所有值。

MapReduce将通过逐步调用该reducer来处理非常大的输入,直到每个键只剩下一个值。