Skip to content


Subversion checkout URL

You can clone with
Download ZIP
An efficient denormalization extension for Mongoid.
Tag: 0.0.3

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.


Mongoid::Max::Denormalize is a denormalization extension for Mongoid.

It was designed for a minimum number of queries to the database.

For now, support only Mongoid 3.

  • Denormalize fields
  • Denormalize methods (only in One to Many situations for now)
  • Denormalize count in Many to One situations
  • Propagate only when needed:
    • for fields: when there are actual changes
    • for methods: always (we can't know in an inexpensive way what is the old value to figure out if there is a change)
  • Take advantage of atomic operations on multiple documents of MongoDB

This is a pre-version not suitable for production.


Add the gem to your Gemfile:

gem 'mongoid_max_denormalize'

Or install with RubyGems:

$ gem install mongoid_max_denormalize


Basic usage

Add include Mongoid::Max::Denormalize in your model and also:

denormalize relation, field_1, field_2 ... field_n, options

Warming up

If there are existing records prior to the denormalization setup, you have to warm up. See below for each relation type.

Note: you can't warm up from both sides of the relation. Only the most efficient is available.

One to Many

Supported fields: normal Mongoid fields, and methods.

Supported options: none.

Example :

class Post
  include Mongoid::Document

  field :title

  def slug

  has_many :comments

class Comment
  include Mongoid::Document
  include Mongoid::Max::Denormalize

  belongs_to :post
  denormalize :post, :title, :slug

@post = Post.create(:title => "Mush from the Wimp")
@comment = @post.comments.create
@comment.post_title #=> "Mush from the Wimp"
@comment.post_slug  #=> "mush-from-the-wimp"

@post.update_attributes(:title => "All Must Share The Burden")
@comment.reload     # to reload the comment from the DB
@comment.post_title #=> "All Must Share The Burden"
@comment.post_slug  #=> "all-must-share-the-burden"

To warm up the denormalization for an existing collection:


Tips : In your views, do not use but @comment.post_id or @comment.post_id? to avoid a query that checks/retrieve for the post. We want to avoid it, don't we ?

Exemple : Check your logs, you'll see queries for the post :

# app/views/comments/_comment.html.erb
<div class="comment">
  <% if %>
    <%= link_to @comment.post_title, %>
  <% end %>

This is better :

# app/views/comments/_comment.html.erb
<div class="comment">
  <% if @comment.post_id? %>
    <%= link_to @comment.post_title, post_path(@comment.post_id, :slug => @comment.post_slug) %>
  <% end %>

Many to One

Supported fields: only normal Mongoid fields (no methods)

Supported options:

  • :count => true : to keep a count !

Example :

class Post
  include Mongoid::Document
  include Mongoid::Max::Denormalize

  has_many :comments
  denormalize :comments, :rating, :stuff, :count => true

class Comment
  include Mongoid::Document

  belongs_to :post

  field :rating
  field :stuff

@post = Post.create(:title => "J'accuse !")
@comment = @post.comments.create(:rating => 5, :stuff => "A")
@comment = @post.comments.create(:rating => 3, :stuff => "B")
@post.comments_count  #=> 2
@post.comments_rating #=> [5, 3]
@post.comments_stuff  #=> ["A", "B"]

To warm up the denormalization for an existing collection:


You can see that each denormalized field in stored in a separate array. This is wanted. An option :group will come to allow the way below (and maybe permit methods denormalization) :

@post.comments_fields #=> [{:rating => 5, :stuff => "A"}, {:rating => 5, :stuff => "B"}]

Many to One

To come...


  • Support for Many to Many
  • Support for :group option in Many to One
  • Support for methods denormalization in Many to One (depends on :group option)
  • Support for :sum and :mean options in Many to One
  • Support for :touch option to "touch" an updated_at field (for cache purpose)


Contributions and bug reports are welcome.

Clone the repository and run bundle install to setup the development environment.

Provide a case spec according to your changes/needs, taking example on existing ones (in spec/cases).

To run the specs:

bundle exec rspec


License - Report a bug.

Something went wrong with that request. Please try again.