Mongoid:如何实现嵌入式文档之间的关系?

时间:2013-04-24 22:11:05

标签: ruby mongoid

我的情况是我有一个父文档,我希望有两种不同类型的嵌入文档:一个作为父文件,另一个作为具有可选父文件的子文档。例如:

class ParentDoc
  include Mongoid::Document
  embeds_many :special_docs
  embeds_many :special_doc_groupings
end

class SpecialDoc
  include Mongoid::Document
  embedded_in :parent_doc
  belongs_to :special_doc_groupings
end

class SpecialDocGrouping
  include Mongoid::Document
  embedded_in :parent_doc
  has_many :special_docs
end

在此示例中,SpecialDocs和SpecialDocGroupings可以不存在关系,也可以选择具有父子关系。

但是,这是一个无效的Mongoid关联,因为我们收到此错误:

  

Mongoid ::错误:: MixedRelations:

     

问题:   由于SpecialDoc是嵌入式的,因此不允许通过关系关联从SpecialDocGrouping文档引用(n)SpecialDoc文档。

     

要点:   为了从SpecialDocGrouping正确访问(n)SpecialDoc,引用需要通过SpecialDoc的根文档。在一个简单的例子中,这将需要Mongoid为根存储额外的外键,在更复杂的情况下,SpecialDoc是多层深度,需要为层次结构中的每个父级存储一个密钥。

     

分辨率:   请考虑不嵌入SpecialDoc,或者在应用程序代码中以自定义方式执行密钥存储和访问。

我没有看到我正在尝试创建的关联类型有任何问题,除了Mongoid不支持它。

我如何自己实现这种类型的关联?

1 个答案:

答案 0 :(得分:10)

该关联无效,因为当您引用嵌入式模型时,Mongoid不会将父键存储为外键。 这意味着如果你有:

Class Parent        
   embeds_many :children
end 

Class Child
   embedded_in :parent
end

您不能引用仅存储其外键的子文档,但是您需要存储所有父键,直到到达根。 在这种情况下,根由第一个父表示,您需要存储2个键。

您可以手动完成此操作,并毫无问题地创建此类关联。

您的情况稍有不同(并且更容易),因为您想要在同一父代中嵌入的两个模型之间创建关联。这意味着理论上您不需要存储父键,因为模型共享相同的根。 Mongoid不处理这种情况,因此您需要手动创建关联规则和方法。

Class Bar
  embeds_many :beers
  embeds_many :glasses
end

Class Beer
  embedded_in :bar
  # Manual has_many :glasses association
  def parent
     self.bar
  end

  def glasses
     parent.glasses.where(:beer_id => self.id)
  end

end

Class Glass
   embedded_in :bar
   # Manual belongs_to :beer association
   field :beer_id, type: Moped::BSON::ObjectId
   def parent
      self.bar
   end

   def beer
      parent.beers.find(self.beer_id)
   end
end

(代码未经过测试)