在mongodb中重新加入分裂的MapReduce阵列

Rejoining Split MapReduce Arrays in Mongo

本文关键字:MapReduce 阵列 分裂 新加入 mongodb      更新时间:2023-09-26

我正在学习mapReduce。在一个用户集合上调用下面的map reduce函数:

function () {
    m = function () {
            emit(this.city, {num:1, arr:this});
    }
    r = function (key, arr_values) {
            var resultArray = [];
            var count = 0;
            arr_values.forEach(function (value) {
                                    resultArray.push(value);
                                    count++;
                                });
            return {num:count, arr:resultArray};
    }
    res = db.AdsOnPage.mapReduce(m, r, {out:"ReducedCollection"});

}

最终得到了我所需要的——"city"作为键,然后是该城市的用户数组作为值。但实际上它给我的是一堆嵌套数组。我想这是分片的结果吧?但我如何重新加入一切?现在,结果看起来像这样:

{
  "city":"Chicago",
  "value" : {
    "num" : 2.0,
    "arr" : [{
        "num" : 2.0,
        "arr" : [{
            "num" : 1.0,
            "arr" : [{
                <user doc is here>
              }]
          }, {
            "num" : 1.0,
            "arr" : [{
                <user doc is here>
              }]
          }]
      }
.......
for many many arrays

为什么会发生这种情况?有没有办法重新加入我的结果到一个连贯的单一数组?

与分片无关,这与Map/Reduce逻辑有关。

map函数得到的value需要具有与从reduce返回的相同的形状。

请记住,reduce可以多次运行。事实上,在分片的情况下,它将为每个分片运行一次,然后再由mongos发出请求。

你在想当你跑的时候会发生什么

reduce(key, [a,b,c])

要使Map/Reduce工作,输出必须与以下相同:

reduce(key, [a, reduce(key, [b,c]) ) OR

reduce(key, [reduce(key, [a,b]), c] )

在您的例子中,reduce(key, [b,c])返回一个数组,因此您得到以下内容:

reduce(key, [a, reduce(key, [b,c]) ) => reduce(key, [a, [b,c] ])

注意到额外的数组了吗?这就是为什么你得到嵌套。

解决这个问题需要两部分。

  1. 如果values是一个数组,那么emit应该输出一个包含一个项目的数组。
  2. 当你做这个改变时,arr_values将是一个"数组的数组"。你必须正确地组合它们。

希望这能给你指明正确的方向。有关更详细的调试方法,您可能需要查看故障排除M/r页面

我使用数组函数array. isarray (param)和indexOf(param)来解决这种问题,但我在堆栈数组中推送唯一元素。

if(Array.isArray(param)) {
    for(var i in param) {
       if(stack.indexOf(param[i]) == -1)
           arr.push(param[i]) ;
    }
}
else {
    if(stack.indexOf(param) == -1)
        arr.push(param) ;
}

你可以尝试Array.isArray()