是否可以在MongoDB中迭代mapReduce

时间:2012-09-28 13:34:40

标签: mongodb mapreduce aggregation-framework

我在MongoDB中使用mapReduce为用户形成他/她的朋友网络的热门歌曲。所以我迭代所有用户并检查user_id是否存在于他们的朋友阵列中,如果它存在我发出他们的歌曲然后合并整个发出的歌曲以找到他所有朋友网络的顶级歌曲。

问题在于我需要遍历所有用户以查找集合中每个用户的(网络趋势歌曲)。我怎样才能实现这一点,有没有像嵌套mapReduce那样的方法。或者我是否必须从应用程序层进行迭代,例如通过for循环来擦除mapReduce!

我正在使用的当前mapReduce就是这个:

var map = function() {
users = [];
songs = [];
    if(this.value.friends !== undefined && this.value.friends.length !== 0 && this.value.songs !== undefined && this.value.songs.length !== 0){
        key = this._id.user_id;
        for(var x=0; x<this.value.songs.length; x++)
            emit({user_id:user_id,song_id:this.value.songs[x][0]},{played:this.value.songs[x][1], counter:1});
    }
};
var reduce = function(key, values) {
    var counter = 0;
    var played = 0;
    values.forEach(function(val){
        counter += val.counter;
        played += val.played;
    });
    return {played : played, counter : counter};
};
db.runCommand({"mapreduce":"trending_users", "map":map, "reduce":reduce, "scope":{user_id: "111222333444"} ,"query":{'value.friends':{$in : ['111222333444'] }},'out':{merge:'trending_user_network'}})    
db.trending_user_network.find({'_id.user_id':'111222333444'}).sort({'value.counter':-1, 'value.played':-1})

1 个答案:

答案 0 :(得分:0)

您当然可以在应用程序中使用for循环来循环访问用户ID并为每个用户ID运行map reduce。但是,对于类似这样的事情,您可能会更好地使用aggregation framework创建一个聚合操作管道来一次完成所有操作。

我不知道您的架构的确切细节,但我认为您可以按照以下方式构建聚合管道:

  • $unwind获取映射到其朋友的用户ID的用户的平面列表
  • $unwind再次将朋友的用户ID映射到他们的歌曲列表
  • $group获取结果列表中每首歌曲的聚合
  • $sort按顺序放置生成的内容

实际上你的管道可能需要更多的步骤,但我认为如果从聚合而不是map-reduce的角度来看这个问题,它会更容易。