与map / reduce mongodb的聚合

时间:2011-12-17 18:51:33

标签: mongodb mapreduce

我有分层组织的数据,我想在单个mongodb map / reduce操作中计算多个级别的聚合。有没有办法做到这一点?

示例:

{ street: "A", district: "1", city: "Z", nb_users: 1 }
{ street: "A", district: "1", city: "Z", nb_users: 2 }
{ street: "B", district: "1", city: "Z", nb_users: 3 }
{ street: "B", district: "1", city: "Z", nb_users: 2 }
{ street: "C", district: "1", city: "Z", nb_users: 4 }
{ street: "C", district: "1", city: "Z", nb_users: 3 }
{ street: "A", district: "2", city: "Z", nb_users: 5 }
{ street: "B", district: "2", city: "Z", nb_users: 6 }
{ street: "B", district: "2", city: "Z", nb_users: 3 }

结果:

{ street: "A", district: "1", city: "Z", nb_users_street: 3, nb_users_district: 15, nb_users_city: 29 }
{ street: "B", district: "1", city: "Z", nb_users_street: 5, nb_users_district: 15, nb_users_city: 29 }
{ street: "C", district: "1", city: "Z", nb_users_street: 7, nb_users_district: 15, nb_users_city: 29 }
{ street: "A", district: "2", city: "Z", nb_users_street: 5, nb_users_district: 14, nb_users_city: 29 }
{ street: "B", district: "2", city: "Z", nb_users_street: 9, nb_users_district: 14, nb_users_city: 29 }

感谢您的帮助!

2 个答案:

答案 0 :(得分:0)

不,没有简单的方法可以做到这一点。

由于您希望按streetdistrict city进行汇总,因此您需要将所有这些内容用作发出的密钥的一部分对象,所以你的map函数很可能看起来像这样:

function(){
  emit ( 
    { street : this.street, district : this.district, city : this.city }, 
    {nb_users : this.nb_users } 
  );
} 

由于reduce功能仅将 记录与匹配的键组合在一起,因此您只能组合街道,地区和城市相同的记录 - 这意味着您将无法计算区域或城市在这些发射物体跨越多条街道时的总数。

将三个单独的map / reduce缩减为三个单独的输出集合将使代码更简单,更易于理解,并且还将消除为每个街道级别行重复nb_users_districtnb_users_city的冗余。

事实上,三个独立的map / reduce函数非常简单,你应该能够使用MongoDB的内置group函数,我认为这比标准map / reduce提供了一些性能优势。

答案 1 :(得分:0)

MongoDB 2.2将引入一个新的聚合框架,它将更快,并且可能能够更好地处理这种情况。但是,我同意Russell的说法,从长远来看,使用3 m / r将会非常简单。如果您想将最终文档调整为下面的其他内容,您可以在单个m / r中进行调整,但代码变得非常繁琐。但是,它确实具有更像文档的好处。

result: {
  city: "Z",
  nb_users: 29
  districts: {
    "1": {
      nb_users: 15,
      streets: {
        "A": 3,
        "B": 5,
        "C": 7
      }    
    },
    "2" : {
      nb_users: 14,
      streets: {
        "A": 5,
        "B": 9
      }   
    }
  }
}