2014-03-05 91 views
0

我有一个很大的歌曲集合,并希望每周获得最多播放歌曲的数组。作为例子:Mongodb Mapreduce加入阵列

{ 
    "_id" : { 
     "title" : "demons savaites hitas", 
     "name" : "imagine dragons" 
    }, 
    "value" : { 
     "weeks" : [ 
      { 
       "played" : 56, 
       "week" : 9, 
       "year" : 2014 
      } 
     ] 
    } 
} 

它有时会:

{ 
    "_id" : { 
     "title" : "", 
     "name" : "top 15" 
    }, 
    "value" : { 
     "played" : 1, 
     "week" : 8, 
     "year" : 2014 
    } 
} 

这是我从被命名的歌曲和新的领域会添加时会添加一个歌曲所有的时间获取数据的集合。没有独特的artistnames或songtitles和集合中的每个文件看起来是这样的:

{ 
    "_id" : ObjectId("530536e3d4ca1a783342f1c8"), 
    "week" : 8, 
    "artistname" : "City Shakerz", 
    "songtitle" : "Love Somebody (Summer 2012 Mix Edit)", 
    "year" : 2014, 
    "date" : ISODate("2014-02-19T22:57:39.926Z") 
} 

我现在想要做的映射缩减其新的一周添加到阵列。它现在覆盖它。 我也注意到当尝试改变为一个数组时,并不是所有的玩家都会使用新的mapreduce进行计数。

新的MapReduce不工作,与周:

map = function() { 
if (this.week == 9 && this.year == 2014) emit({title:this.songtitle.toLowerCase(), name:this.artistname.toLowerCase()}, {played:1, week:this.week, year:this.year}); 
} 
reduce = function(k, values) { 

var result = {}; 
result.weeks = new Array(); 
var object = {played:0, week: 0, year: 0}; 
values.forEach(function(value) { 
    object.played += value.played; 
    object.week = value.week; 
    object.year = value.year; 
}); 
result.weeks.push(object); 
return result; 
} 
db.songs.mapReduce(map,reduce,{out: {reduce:"played2"}}) 

这是旧的我使用的是为每周和歌曲集合在一个新的领域:

map = function() { 
if (this.week == 10 && this.year == 2014) emit({title:this.songtitle.toLowerCase(), name:this.artistname.toLowerCase(), week:this.week, year:this.year}, {count:1}); 
} 
reduce = function(k, values) { 
var result = {count: 0,}; 
values.forEach(function(value) { 
result.count += value.count; 
}); 
return result; 
} 
db.songs.mapReduce(map,reduce,{out: {merge:"played"}}) 

我现在得到played2这样来回toplist的信息:

db.played2.find({'_id.week': 9,'_id.year': 2014}).sort(array("value.count" => -1)).limit(50) 

以上线可以包括任何错字,因为我使用PHP的MongoClient并需要将其更改为JavaScript语法。

我在做什么错?

+0

你可以包括你的**原始**集合的结构是什么。我的观点是我不认为你想要mapReduce,这可能会有更好的方法。 –

+0

@NeilLunn - 我已经用文档编辑了这些问题以及该集合如何工作。它只是最后播放歌曲的一个长时间的收藏集,所有时间都会添加新歌,大约每秒10个。 –

+0

尝试回答中的聚合语句。聚合管道的运行速度比map reduce快得多,这似乎适合您的预期结果。 –

回答

1

我发现我可以做mapreduce作为上面的代码片段,然后在本周查询中获得另一个前一周的数据,并且使用if来更新本周的前一周。

我在python中创建脚本,我也为我的mapreduce运行cronjob。例如:

if len(sys.argv) > 1 and sys.argv[1] is not None: 
    week = int(sys.argv[1]) 
else: 
    week = (datetime.date.today().isocalendar()[1]) - 1 

year = datetime.date.today().year 

previous_week = week - 1 

client = MongoClient() 
db = client.db 
played = db.played 

print "Updating it for week: " + str(week) 

previous = played.find({"_id.week": previous_week, "_id.year": year}).sort("value.count", -1).limit(50) 
thisweek = played.find({"_id.week": week, "_id.year": year}).sort("value.count", -1).limit(50) 

thisplace = 1 
for f in thisweek: 
    previous.rewind() # Reset second_collection_records's iterator 
    place = 1 

    if previous.count() > 0: 
     checker = bool(1) 
     for s in previous: 
      if s["_id"]["name"] == f["_id"]["name"] and s["_id"]["title"] == f["_id"]["title"]: 
       result = played.update({"_id.week": f["_id"]["week"], "_id.year": f["_id"]["year"], "_id.title": f["_id"]["title"], "_id.name": f["_id"]["name"]}, {"$set": {"place.previous_week":place, "place.this_week":thisplace}}) 
       checker = bool(0) 
       print result 
      place = place + 1 
     if checker is True: 
      result = played.update({"_id.week": f["_id"]["week"], "_id.year": f["_id"]["year"], "_id.title": f["_id"]["title"], "_id.name": f["_id"]["name"]}, {"$set": {"place.previous_week":0, "place.this_week":thisplace}}) 
      print result 
    else: 
     result = played.update({"_id.week": f["_id"]["week"], "_id.year": f["_id"]["year"], "_id.title": f["_id"]["title"], "_id.name": f["_id"]["name"]}, {"$set": {"place.previous_week":0, "place.this_week":thisplace}}) 
     print result 
    thisplace = thisplace + 1 

print "done." 

这似乎工作得很好。希望mongodb增加对仅更新mapreduce中的字段或任何内容的支持,以将信息添加到文档而不会覆盖它。

0

我正在根据你的输入字段刺探你的集合的结构,但我不认为mapReduce是你想要的工具。可以使用aggregate实现你明显所需的输出:

db.collection.aggregate([ 
    // Match a specific week and year if you want - remove if you want all 
    { "$match": { "year": inputYear, "week": inputWeek } }, 

    // Group to get the total number of times played 
    { "$group": { 
     "_id": { 
      "title": { "$toLower": "$songtitle" }, 
      "name": { "$toLower": "$artistname" }, 
      "week": "$week", 
      "year": "$year" 
     }, 
     played: { "$sum": 1 } 
    }}, 

    // Sort the results by the most played in the range 
    { "$sort": { "year": -1, "week": -1, "played": -1 } }, 

    // Optionally limit to the top 15 results 
    { "$limit": 15 } 

]) 

,基本上就是你看起来是试图做。所以这总结了“出场次数”与次数的关系。然后,我们采取额外的步骤对结果进行排序,并且(可选)(如果您可以同时查找一周),则会将结果限制为一组数字。最后两步你不会用mapReduce获得。

如果您最终每周都在寻找“前十名”,作为单个查询结果,那么您可以通过look at this进行讨论(以及实现方法),我们称之为“topN”结果问题。

+0

我在发布的查询中得到了'错误:第13行:意外的标记{'在此查询中 –

+0

@HåkanNylén错字。在组声明中缺少一个右括号 –