2010-07-15 40 views
3

我剛剛開始一個使用Mongoid ORM for MongoDB的新Rails 3項目。只有一件事我無法理解,那就是如何有效地建立多對多的關係。現在我很有可能錯誤地處理這個問題,但據我所知,在我的項目中至少有兩個容器需要多對多的關係。我寧願將這兩個模型都視爲「頭等艙」模型,並將它們分配給各自的容器。重新思考MongoDB的關係多對多關係

這是我能想到的構建最簡單的方法我的許多一對多的關係:

// Javascript pseudo modeling 
// -------------------- Apps 
{ 
    app: { 
    _id: "app1", 
    name: "A", 
    event_ids: ["event1","event2"] 
    } 
} 

{ 
    app: { 
    _id: "app2", 
    name: "B", 
    event_ids: ["event1"] 
    } 
} 

// -------------------- Events 

{ 
    event: { 
    _id: "event1", 
    name: "Event 1", 
    } 
} 

{ 
    event: { 
    _id: "event2", 
    name: "Event 2", 
    } 
} 

據我可以告訴這是最少量信息需要推斷一個多TO-很多關係。我的假設是,我可能必須有一個地圖縮小程序來確定哪些應用程序屬於一個事件。如果應用程序添加到事件模型或從事件模型中刪除,我還必須在事件上編寫提交/保存掛鉤以更新App.event_ids。

我在正確的軌道上嗎?如果有人有任何Mongoid或Mongomapper代碼的多對多關係示例工作,請分享一下。

回答

1

我能夠使用Mongoid來實現這個設計。我寫了大量的測試,並且能夠解決我的解決方案;然而,我對我的實施並不滿意。我相信我的實施會很難維持。

我在這裏發佈我的非優雅的解決方案。希望這可以幫助開始更好實施的人。

class App 
    include Mongoid::Document 
    field :name 

    references_one :account 
    references_many :events, :stored_as => :array, :inverse_of => :apps 

    validates_presence_of :name 
end 

class Event 
    include Mongoid::Document 
    field :name, :type => String 

    references_one :account 

    validates_presence_of :name, :account 

    before_destroy :remove_app_associations 

    def apps 
    App.where(:event_ids => self.id).to_a 
    end 

    def apps= app_array 
    unless app_array.kind_of?(Array) 
     app_array = [app_array] 
    end 
    # disassociate existing apps that are not included in app_array 
    disassociate_apps App.where(:event_ids => self.id).excludes(:id => app_array.map(&:id)).to_a 
    # find existing app relationship ids 
    existing_relationship_ids = App.where(:event_ids => self.id, :only => [:id]).map(&:id) 
    # filter out existing relationship ids before making the new relationship to app 
    push_apps app_array.reject { |app| existing_relationship_ids.include?(app.id) } 
    end 

    def push_app app 
    unless app.event_ids.include?(self.id) 
     app.event_ids << self.id 
     app.save! 
    end 
    end 

    def disassociate_app app 
    if app.event_ids.include?(self.id) 
     app.event_ids -= [self.id] 
     app.save! 
    end 
    end 

    def push_apps app_array 
    app_array.each { |app| push_app(app) } 
    end 

    def disassociate_apps app_array 
    app_array.each { |app| disassociate_app(app) } 
    end 

    def remove_app_associations 
    disassociate_apps apps 
    end 

end 
1

您的結構可以工作,並且您不需要使用mapreduce函數來確定哪些應用程序屬於某個事件。您可以在一個eventid上查詢應用程序集合。您可以將字段collection.event_ids編入索引。

如果您不想在eventid上搜索應用程序,而是在事件名稱上搜索應用程序,則需要將該事件名稱添加到應用程序集合(非規範化)中。這意味着當事件名稱更改時,您還必須更新應用程序集合。我不知道這是否經常發生?

當你使用MongoDB時,你經常需要非規範化,所以你不會存儲最少量的信息,但是你會存儲一些「兩次」的東西。

+0

謝謝。這是我採取的方法。我張貼我如何實施下面。 – 2010-07-19 20:31:16