I can't find any blog post or documentation talking about this. They both, embedded document and hash data type, are quite similar. What the benefit or limitation of each over the other?
Consider my schema design:
class HistoryTracker
include ::Mongoid::Document
include ::Mongoid::Timestamps
field :modifier, type: Hash, default: {}
field :original, type: Hash, default: {}
field :modified, type: Hash, default: {}
field :changeset, type: Hash, default: {}
end
Should I create several embedded document inside this HistoryTracker class? or just use that? How about indexing?
Mongoid stores embedded documents and Hash attributes in pretty much the same way at the database level. Its normal when working with mongoid to declare your fields in your models so if you have a nested structure its normal to create an embedded document. Because MongoDB is schema-less mongoid needs you to declare fields in order to present them in the same kind of API that ActiveRecord does. But for some use cases a Hash attribute gives you a bit more flexibility. The downside of that flexibility is that you are limited to the Hash API so you don't get auto-generated attribute methods and you can't encapsulate business logic in the way that you might normally do within a model class.
As an example, suppose you have a Questionnaire model in which you need to store many sections containing many question-answer pairs. If a key requirement of the system is for the administrator to be able to setup new sections and questions then you would not easily be able model the answers as a regular embedded document containing explicit fields for each question. For that kind of thing a Hash might make more sense.
I don't know what your specific requirements are but as a rough guide I would say that when you are working with a fixed schema stick with an embedded document, but when you need an open-ended model consider Hash attributes.
With an embedded document you also have attribute aliases, as in
class Outer
include Mongoid::Document
embeds_one :inner_informative_object_with_long_name, store_as: :inn
end
class Embedded
include Mongoid::Document
attribute :vvla, as: :very_very_long_attribute, type: String
end
so in the database you have short names (much less memory used) and you use the long ones in your code.
A problem I ran into with using Hashes instead of embedded documents
When Mongoid is about to serialize a document, it currently does not look at nested values of hashes and assumes they are already serialized.
so if you wanted to have a "Hash dump" like the following
class Event
include Mongoid::Document
field :properties, type: Hash
end
Then you CANNOT use objects in the properties
class Foo
include Mongoid::DOcument
end
e = Event.new(
properties: {
some_info: Foo.new
}
}
Trying to persist the following event will cause a crash because Foo will not be serialized (try e.as_document
and you'll see the value of some_info
will not be serialized)
references to the issues : Github, MongoDB tracker