麻烦使用Map Reduce旋转数据

时间:2013-08-16 01:24:43

标签: javascript mongodb for-loop mapreduce

我无法使用map reduce旋转数据集。我一直在使用MongoDB食谱来寻求帮助,但我得到了一些奇怪的错误。我想采用以下集合并对其进行调整,以便每个用户都有一个包含所有评论评级的列表。

我的收藏如下:

{
  'type': 'review',
  'business_id': (encrypted business id),
  'user_id': (encrypted user id),
  'stars': (star rating),
  'text': (review text),
}

Map函数(用Python包装):

map = Code(""""
function(){
key = {user : this.user_id};
value = {ratings: [this.business_id, this.stars]};

emit(key, value);
}
""")

map函数应返回与键关联的值数组... 减少函数(用Python包装):

reduce = Code("""
function(key, values){
var result = { value: [] };
temp = [];

for (var i = 0; i < values.length; i++){
temp.push(values[i].ratings);
}
result.value = temp;
return result;
}
""")

然而,结果返回少于评级的总和。实际上,有些用户已经返回None,这是不可能的。有些条目如下所示:

{u'_id': {u'user: u'zwZytzNIayFoQVEG8Xcvxw'}, u'value': [None, [u'e9nN4XxjdHj4qtKCOPQ_vg', 3.0], None, [...]...]

我无法确定代码中的内容是什么造成的。如果有3条评论,则它们都在文档中包含业务ID和评级。另外,在我的循环条件中使用'values.length + 1'会因某种原因中断值[i]。

修改1

我已经接受了这样一个事实,即自身会多次调用reduce,所以下面是我的新减速器。这将返回[业务,评级,业务,评级]的数组。知道如何输出[业务,评级]数组而不是一个巨型阵列吗?

function(key, value){
var result = { ratings:[] };
var temp = [];
values.forEach(function(value){
    value.ratings.forEach(function(rating){
        if(temp.indexof(rating) == -1){
            temp.push(rating);
        }
    });
});

result. rartings = temp;
return result;
}

1 个答案:

答案 0 :(得分:1)

下面是一个测试例子:

1)添加一些样本数据:

db.test.drop();
db.test.insert(
  [{
    'type': 'review',
    'business_id': 1,
    'user_id': 1,
    'stars': 1,
  },
  {
    'type': 'review',
    'business_id': 2,
    'user_id': 1,
    'stars': 2,
  },
  {
    'type': 'review',
    'business_id': 2,
    'user_id': 2,
    'stars': 3,
  }]
);

2)地图功能

var map = function() {
  emit(this.user_id, [[this.business_id, this.stars]]);
};

这里我们设置结果,因为我们希望它们在过程结束时看起来像。为什么?因为如果用户只进行过一次审核(我们正在分组的关键字),那么结果将不会经历减少阶段。

3)减少功能

var reduce = function(key, values) {
  var result = { ratings: [] };
  values.forEach(function(value){
    result.ratings.push(value[0]);
  });

  return result;
};

这里我们收集所有的值,记住我们在map方法中嵌套它们,所以我们可以为每组结果挑选出第一个值。

4)运行map reduce:

db.test.mapReduce(map, reduce, {finalize: final, out: { inline: 1 }});

替代方案 - 使用aggregation framework

db.test.aggregate({
  $group: {
    _id: "$user_id", 
    ratings: {$addToSet: {business_id: "$business_id", stars: "$stars"}}
  }
});