2014-03-05 88 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錯字。在組聲明中缺少一個右括號 –