Counter Caching with MongoMapper

MongoMapper makes column based counter caching simple. I think you'll be delighted.

What is counter caching?

Counter caching is a way to display the record count (or total - using the term loosely) for a has_many assocation. Ryan Bates did a screencast on it and many apps today employ counter caching. (aside: You should be doing things like counter caching before you just go and grab memcache.)

For example, I am building an application that keeps track of pilots' flights. A pilot is able to log their flights, and the application returns their total flights count. At first I displayed this value using Flight.count(:user_id => id) in the view. This was ok at first, but once a pilot had one thousand flights, page load times were noticeably longer so I added a counter cache column.

Counter caching works well. I received some significant speed improvements.

Ok, let's get on it with it.

How to setup counter caching in MongoMapper

Scenario

I want to store the sum of a column in a cache. In my application a User has many Flights, and each flight has fields like hours, landings, night_hours, etc. I want to have methods like @user.total_hours, @user.total_landings, and @user.total_night_hours that cache themselves so my app can get similar speed advantages like you saw above.

To do this, I:

  1. Added @user.total_something instance methods to my User model.
  2. Added callbacks in my Flight model to clear the cache whenever the pilot adds/updates/destroys a flight.

Step #1: Add the instance methods to User.rb

Step #2: Add the clear cache callbacks to Flight.rb

That's it. You're done. You can now use @user.total_hours, @user.total_landings, etc in your views and your app will stay snappy.

Conclusion

Counter caching with MongoMapper ended up being just 14 lines of code. You don't have to hassle with migrations and you can meta-program your schema into the model. (Thanks to John Nunemaker for building it that way. Thought: I really don't like the way ActiveRecord uses migrations. Plus, it decouples the schema from the model.). It works with floating point numbers too.

Keep updated at twitter.com/spitfiresky