重新思考MongoDB的多对多关系
我刚刚开始一个新的Rails 3项目,使用Mongoid ORM for MongoDB。只有一件事我无法理解,那就是如何有效地建立多对多关系。现在,我很有可能错误地处理了这个问题,但据我所知,我的项目中至少有两个容器需要多对多关系。我更愿意将这两个模型视为“第一类”模型,并为每个模型分配自己的容器 这是我能想到的构建多对多关系的最简单方式:重新思考MongoDB的多对多关系,mongodb,ruby-on-rails-3,mongomapper,mongoid,Mongodb,Ruby On Rails 3,Mongomapper,Mongoid,我刚刚开始一个新的Rails 3项目,使用Mongoid ORM for MongoDB。只有一件事我无法理解,那就是如何有效地建立多对多关系。现在,我很有可能错误地处理了这个问题,但据我所知,我的项目中至少有两个容器需要多对多关系。我更愿意将这两个模型视为“第一类”模型,并为每个模型分配自己的容器 这是我能想到的构建多对多关系的最简单方式: // Javascript pseudo modeling // -------------------- Apps { app: { _i
// 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过程来确定哪些应用属于某个事件。如果在事件模型中添加或删除应用程序,我还必须在事件上编写post commit/save hook来更新App.Event_id
我走对了吗?如果有人有任何多对多关系的Mongoid或Mongomapper代码示例,请分享。您的结构可以工作,您不需要mapreduce函数来确定哪些应用属于某个事件。您可以在eventid上查询应用程序集合。您可以为字段collection.event\u id编制索引 如果您不想在eventid上搜索应用程序,而是在事件名称上搜索应用程序,则需要将该事件名称添加到应用程序集合(非规范化)。这意味着您还必须在事件名称更改时更新应用程序集合。我不知道这种情况是否经常发生
当您使用MongoDB时,您经常需要进行非规范化,因此您不需要存储最小数量的信息,而是可以“两次”存储某些内容 我能够使用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
类事件
include Mongoid::Document
字段:name,:type=>String
参考文献1:账户
验证是否存在:name、:account
销毁前:删除应用程序关联
def应用程序
App.where(:event\u id=>self.id).to\u a
结束
def apps=app_数组
除非应用程序数组。类型?(数组)
应用程序数组=[应用程序数组]
结束
#解除未包含在应用程序数组中的现有应用程序的关联
将应用程序App.where(:event\u id=>self.id)。排除(:id=>App\u array.map(&:id))。与
#查找现有应用程序关系ID
现有的_关系_id=App.where(:event_id=>self.id,:only=>[:id]).map(&:id)
#在与应用程序建立新关系之前,筛选出现有关系ID
push|apps app|array.reject{| app|现有的_关系_id.include?(app.id)}
结束
def推送应用程序
除非app.event\u id.include?(self.id)
app.event\u id谢谢。这就是我采取的方法。我在下面发布我是如何实现这一点的。
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