我的情况是我有一个父文档,我希望有两种不同类型的嵌入文档:一个作为父文件,另一个作为具有可选父文件的子文档。例如:
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不支持它。
我如何自己实现这种类型的关联?
答案 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
(代码未经过测试)