2010-12-02 64 views
9

我有以下型號如何執行獨特的嵌入式文件mongoid

class Person 
    include Mongoid::Document 
    embeds_many :tasks 
end 

class Task 
    include Mongoid::Document 
    embedded_in :commit, :inverse_of => :tasks 
    field :name 
end 

如何確保以下?

person.tasks.create :name => "create facebook killer" 
person.tasks.create :name => "create facebook killer" 

person.tasks.count == 1 

different_person.tasks.create :name => "create facebook killer" 
person.tasks.count == 1 
different_person.tasks.count == 1 

即任務名稱是一個特定的人


內唯一已經檢查了有關索引的文檔我認爲以下可能的工作:

class Person 
    include Mongoid::Document 
    embeds_many :tasks 

    index [ 
     ["tasks.name", Mongo::ASCENDING], 
     ["_id", Mongo::ASCENDING] 
    ], :unique => true 
end 

person.tasks.create :name => "create facebook killer" 
person.tasks.create :name => "create facebook killer" 

還在生產取得重複。上述人士表示


指數的配置將轉化爲對MongoDB的

db.things.ensureIndex({firstname : 1, 'tasks.name' : 1}, {unique : true}) 

回答

1

索引是默認情況下不唯一。如果你看看這個Mongo Docs,唯一性是一個額外的標誌。

我不知道確切的Mongoid翻譯,但你正在尋找的東西是這樣的:

db.things.ensureIndex({firstname : 1}, {unique : true, dropDups : true})

+0

我添加細節的什麼人指數的配置將是問題翻譯成mongodb。它不包括dropDups:true,所以我會看看這個。 – opsb 2010-12-02 21:12:24

+0

看來dropDups僅在首次創建新索引時使用,因此它不會解決我的問題。 – opsb 2010-12-02 21:14:26

4

你就不能把一個驗證的任務?

validates :name, :uniqueness => true 

這應該確保父文檔內的唯一性。

0

我不認爲這是可能的嵌入式文件。我遇到了同樣的問題,唯一的解決方法是使用引用文檔,而不是嵌入文檔,然後在引用文檔上創建複合索引。

顯然,唯一性驗證是不夠的,因爲它無法防範競爭條件。我遇到的唯一索引的另一個問題是,mongoid的默認行爲是,如果驗證通過並且數據庫拒絕接受文檔,則不會引發任何錯誤。我不得不改變下面的配置選項mongoid.yml:

persist_in_safe_mode: true 

這是在http://mongoid.org/docs/installation/configuration.html

最後記錄在案,進行此更改後,保存/ create方法將開始,如果數據庫拒絕拋出一個錯誤存儲文檔。所以,你需要像這樣的東西能夠告訴用戶發生了什麼:

alias_method :explosive_save, :save 

def save 
    begin 
    explosive_save 
    rescue Exception => e 
    logger.warn("Unable to save record: #{self.to_yaml}. Error: #{e}") 
    errors[:base] << "Please correct the errors in your form" 
    false 
    end 
end 

即使這是不是真的一個很好的選擇,因爲你留下猜測哪個領域真正導致錯誤(和爲什麼)。更好的解決方案是查看MongoidError內部並相應地創建適當的錯誤消息。以上符合我的申請,所以我沒有走得這麼遠。

0

添加驗證檢查,將嵌入式任務ID的數組數與另一個具有唯一ID的數組的計數進行比較。

validates_each :tasks do |record, attr, tasks| 
    ids = tasks.map { |t| t._id } 
    record.errors.add :tasks, "Cannot have the same task more than once." unless ids.count == ids.uniq.count 
end 

爲我工作。

-1

你必須運行:

db.things.ensureIndex({firstname : 1, 'tasks.name' : 1}, {unique : true}) 

直接對數據庫

你似乎包括一個 「create index命令」 您的 「活動記錄」 內的(即類Person)

0

你可以在你的任務模型中定義一個validates_uniqueness_of來確保這一點,根據Mongoid文檔http://mongoid.org/docs/validation.html這個驗證適用於父文檔的範圍,並且應該做你想做的事情。

您的索引技術也應該起作用,但您必須在生效之前生成索引。使用Rails,您可以使用rake任務(在當前版本的Mongoid中稱其爲db:mongoid:create_indexes)執行此操作。請注意,當保存違反索引約束的內容時,您將不會收到錯誤,因爲Mongoid(有關更多信息,請參閱http://mongoid.org/docs/persistence/safe_mode.html)。

0

你也可以在你的模型類指定索引:

index({ 'firstname' => 1, 'tasks.name' => 1}, {unique : true, drop_dups: true }) 

,並使用rake任務

rake db:mongoid:create_indexes