2010-07-15 75 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