2013-04-17 31 views
2

我正在遍歷集合(運行Moped作爲Ruby驅動程序),但如何爲每個文檔更新一個字段?在MongoDB中迭代集合以獲取更新

irb> session = Moped::Session.new(["127.0.0.1:27017"]) 
irb> session.use :demoapp 
irb> users = session[:users] 
irb> users.find.each {|u| u.update(age: rand(18..80))} 

這不更新域 「年齡」,而一個簡單的

irb> users.find.each {|u| users.find(_id: u["_id"]).update(age: rand(18..80))} 

一樣。但是迭代一個集合似乎並不是非常有效,然後在每次迭代中查找id。那麼我怎麼能簡化它呢?我需要一些快速的方法來以這種方式更新數百萬個文檔。

的問候, 克里斯

+0

'users.find.update_all(:$ set => {age:rand(18..80)}})'? – WiredPrairie

+0

@WiredPrairie會將所有文檔設置爲相同(隨機選擇)的年齡。 – Leopd

+0

@Leopd - true。我專注於讓語法高效並且一次調用。 :) – WiredPrairie

回答

1

你更輕便摩托車治療像它的mongoid。輕便摩托車不是一個ODM - 它是一個低級別的mongodb驅動程序。

當您迭代users.find時,您會收到一組簡單的Moped::BSON::Document對象,這些對象比其他任何對象更像是ruby Hash對象。所以當你打電話給update時,你只是更新了內存中的本地設備而沒有觸及數據庫。

同樣

users.find(_id: u["_id"]).update(age: rand(18..80)) 

並不像你想象的那樣糟糕。輕便摩托車將其編譯爲單個update命令 - 它不會獲取文檔,修改它,然後將其寫回。

爲了便於開發,你可能會更快樂實際使用mongoid,像這樣:

class User 
    include Mongoid::Document 
    field :age, type: Integer 
end 

User.all.each do |u| 
    u.age = rand(18..80) 
    u.save! 
end 

但是如果性能是至關重要的,助力車速度更快。您也可以對官方10gen ruby driver進行基準測試。如果你可以將你的代碼移植到javascript,你可以在mongodb服務器本身上運行它,這樣可以消除網絡延遲,但是在你做這些事情時要小心鎖定整個數據庫。

+0

這仍然會獲取每個文檔並單獨設置每個文檔,不是嗎?這只是不同的語法。 – WiredPrairie

+0

它一次性提取它們,或者至少大批量提取它們。它一次寫回一個。 – Leopd

+1

嗨,謝謝你的回覆。 Moped與Mongoid的關係如下:它的性能都是:)我必須更新8百萬個文檔,而且Mongoid比簡單的Moped查詢慢5到6倍,即使驗證被忽略時它太慢了。但我的第一種方法工作正常:) – ctp