I have a situation where I have a parent document and I want to have two different types of embedded documents: one as a parent, and another as a child with an optional parent. For example:
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
In this example, SpecialDocs and SpecialDocGroupings can exist without a relationship, or optionally can have a parent-child relationship.
However, this is an invalid Mongoid association because we get this error:
Mongoid::Errors::MixedRelations:
Problem: Referencing a(n) SpecialDoc document from the SpecialDocGrouping document via a relational association is not allowed since the SpecialDoc is embedded.
Summary: In order to properly access a(n) SpecialDoc from SpecialDocGrouping the reference would need to go through the root document of SpecialDoc. In a simple case this would require Mongoid to store an extra foreign key for the root, in more complex cases where SpecialDoc is multiple levels deep a key would need to be stored for each parent up the hierarchy.
Resolution: Consider not embedding SpecialDoc, or do the key storage and access in a custom manner in the application code.
I don't see anything wrong with the type of association that I'm trying to create, besides the fact that it's not supported by Mongoid.
How can I implement this type of association myself?
The association is not valid because when you reference embedded model Mongoid does not store the parent key as foreign key. This means that if you have:
Class Parent
embeds_many :children
end
Class Child
embedded_in :parent
end
You cannot reference Child document storing only its foreign key, but you need to store all the parents keys until you reach the root. In this case the root is represented by the first parent and you need to store 2 keys.
You can accomplish this manually, and create this type of association without any problem.
Your case is a bit different (and easier) because you want to create the association between two models embedded in the same parent. That means theoretically you don't need to store the parent key because the models share the same root. Mongoid does not handle this scenario, so you need to manually create your association rules, and methods.
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
(the code is not tested)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With