2012-01-26 104 views
4

我只是用Rails潛入Mongodb和MongoID,我覺得它很棒。有一件事NoSQL的幫助時,我可以以我的模型添加額外的字段,而每當我想任何額外的努力:Ruby on Rails和NoSQL,添加字段

class Page 
    include Mongoid::Document 
    include Mongoid::MultiParameterAttributes 
    field :title, :type => String 
    field :body, :type => String 
    field :excerpt, :type => String #Added later 
    field :location, :type => String #Added later 
    field :published_at, :type => Time 

    validates :title, :presence => true 
    validates :body, :presence => true 
    validates :excerpt, :presence => true 
end 

而這完美的作品,因爲它應該。但我的問題是,(對不起,如果這是微不足道的)現有的條目是空白的,沒有爲新添加的字段定義的值。例如,在示例博客應用程序中,在我發佈了兩篇文章後,我決定將一個摘錄和一個位置字段添加到我的數據庫(請參閱上面的代碼)。添加這些新字段後發佈的任何博客帖子都可以確保爲摘錄字段填寫值。但是在添加這兩個新字段之前發佈的帖子具有我無法驗證的空值(這是可以理解的原因)。有沒有一個優雅的解決方案呢?

謝謝。

回答

4

有三種基本選擇:

  1. 更新裏面的一切MongoDB中包含的摘錄。
  2. 使用after_initialize掛鉤可將現有對象從默認摘錄添加到MongoDB中時添加默認摘錄。
  3. 將您的驗證邏輯Kludge檢查是否存在新對象的摘錄。

(1)當您進行更改時需要(可能大)時間命中,但這只是一次性的事情,您不必擔心它。你將每一頁從MongoDB中取出,做page.excerpt = 'some default excerpt',然後將它保存回MongoDB。如果你有很多頁面,你需要一次處理100個數據塊。如果你這樣做,你將能夠搜索摘錄,而不用擔心你應該用null s做什麼。您也可以通過發送做到這裏面的MongoDB一個JavaScript fragment into MongoDB

connection.eval(%q{ 
    db.pages.find({}, { _id: true }).forEach(function(p) { 
     db.pages.update(
      { _id: p._id }, 
      { $set: { excerpt: 'some default excerpt' } } 
     ); 
    }); 
}) 

(2)會去是這樣的:

after_initialize :add_default_excerpt, :unless => :new_record? 
#... 
private 
def add_default_excerpt 
    self.excerpt = 'some default excerpt' unless self.excerpt.present? 
end 

你可以移動unless self.excerpt:unless,如果你不介意使用拉姆達:

after_initialize :add_default_excerpt, :unless => ->{ |o| o.new_record? || o.excerpt.present? } 
#... 
private 
def add_default_excerpt 
    self.excerpt = 'some default excerpt' 
end 

這應該是非常快速和容易設置,但也有缺點。首先,你會在你的MongoDB中有大量的null,你可能不得不在搜索時特別對待它。此外,你會攜帶一堆代碼和邏輯來處理舊數據,但隨着時間的推移,這種行李將會越來越少。此外,after_initialize電話不會免費。

(3)要求您跳過驗證是否存在非新頁面的摘錄(:unless => :new_record?),或者您必須找到一些方法來區分新對象和舊對象,同時也正確處理新和舊對象的編輯舊頁面。您也可以強制人們在更改頁面並按原樣保留驗證時提供摘錄;包括您的field :excerpt上的:default => ''將處理視圖中的任何nil問題等。


如果可能,我會和(1)一起去。如果更新時間過長,並且您在修復MongoDB時想要啓動並運行該站點,則可以在更新時添加:default => '',然後刪除:default選項,重新啓動並手動修補所有通過的錯誤。

+0

謝謝!這是一個非常詳細和解釋清楚的答案,我真正想要的是什麼。 – dsignr