【问题标题】:Rethinking relational many-to-many relationships for MongoDB重新思考 MongoDB 的关系多对多关系
【发布时间】:2010-07-15 23:18:39
【问题描述】:

我刚刚开始一个使用 Mongoid ORM for MongoDB 的新 Rails 3 项目。只有一件事我无法理解,那就是如何有效地建立多对多关系。现在很有可能我可能错误地处理了这个问题,但据我所知,我的项目中至少有两个容器需要多对多关系。我更愿意将这两个模型都视为“一流”模型,并为每个模型分配自己的容器。

这是我能想到的构建多对多关系的最简单方法:

// 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",
  }
}

据我所知,这是推断多对多关系所需的最少信息量。我的假设是我可能必须有一个 map reduce 过程来确定哪些应用程序属于一个事件。如果将应用程序添加到事件模型中或从事件模型中删除,我还必须在 Event 上编写提交提交/保存挂钩以更新 App.event_ids。

我在正确的轨道上吗?如果有人有任何多对多关系的 Mongoid 或 Mongomapper 代码示例,请分享。

【问题讨论】:

    标签: mongodb ruby-on-rails-3 mongomapper mongoid


    【解决方案1】:

    您的结构可以工作,并且您不需要 mapreduce 函数来确定哪些应用属于某个事件。您可以在 eventid 上查询应用程序集合。您可以索引字段 collection.event_ids。

    如果您不想在 eventid 上而是在事件名称上搜索应用程序,则需要将该事件名称添加到应用程序集合中(非规范化)。这意味着您还必须在事件名称更改时更新应用程序集合。不知道是不是经常这样?

    在使用 MongoDB 时,您经常需要进行非规范化,因此您不会存储最少量的信息,而是会“两次”存储一些东西。

    【讨论】:

    • 谢谢。这是我采取的方法。我在下面发布了我是如何实现的。
    【解决方案2】:

    我能够使用 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
    

    【讨论】:

      猜你喜欢
      • 2013-01-02
      • 2018-11-03
      • 1970-01-01
      • 2014-01-21
      • 2014-08-15
      • 2020-12-05
      • 2014-10-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多