One of the great things about MongoDB is the flexible schema. In the past whenever we had to store custom data attributes in relational DBs we had to create separate lookup tables. There would be a preset number of these custom fields with specific data types and separately we stored what their labels should be. Or we would create tables for key/value pairs and do complex lookups. It was a pain. That’s where flexible schema is great.

Let’s say you are building an online shopping mall where different Stores have multiple Orders. With flexible schema your document just shrinks and expands as needed storing different fields for different Order documents (depending on which Store they belong to). We are using Mongoid ODM so our models look like this

class Store
  include Mongoid::Document
  has_many :orders
  field :name,                  type: String
  ...
end
class Order
  include Mongoid::Document
  include Mongoid::Attributes::Dynamic # this enables Mongoid to store dynamic fields
  belongs_to :store
  # list common fields here
  ...
end

But how do you read/write these dynamic attributes from your code? To do that we created a new model which describes these dynamic attributes:

class DynamicAttributes
  include Mongoid::Document
  embedded_in :store
  # there is inverse embeds_many: dynamic_attributes defined in Store model
  field :name,                  type: String
  field :html_control,          type: String # this could be input, boolean or select
  ...
end

In our UI we use this to generate custom HTML for each order form so users can enter the information:

order.store.dynamic_attributes.each do |field|
  # render your HTML
end

And we used order.write_attribute(:field_name_here) and order.read_attribute(:field_name_here) in models/controllers to access the data. This way Order model can have certain common fields and then each store can be configured with dynamic fields. The example above is not what we actually implemented at work but I wanted to simplify things.