Question

I'm using MongoMapper for our primary datastore, and I want to run reporting jobs against the slave nodes in our replica set, rather than the primary. Unfortunately, most of our background jobs are read/write and need to go against the primary.

Is there some way I can do something like the following:

MongoMapper.options({:slave_ok => true})

report.fetch_data  # does all sorts of stuff, uses normal Models, developer doesn't have to go out of his/her way to specify a read preference

MongoMapper.options({:slave_ok => force})

Right now it looks like MongoMapper really just wants you to set read preference as you bring the connection up and then not change it after that.

Was it helpful?

Solution

MM doesn't natively support this, but it wouldn't be too hard to do it on a per-model basis via a plugin.

module MongoMapper
  module Plugins
    module ReadPreference
      extend ActiveSupport::Concern

      included do
        class << self
          attr_accessor :read_preference
        end
      end

      module ClassMethods
        def query(options={})
          options.merge!(:read => read_preference) if read_preference
          super options
        end

        def with_read_preference(preference)
          self.read_preference = preference
          begin
            yield
          ensure
            self.read_preference = nil
          end
        end
      end
    end
  end
end

MongoMapper::Document.plugin(MongoMapper::Plugins::ReadPreference)

And testing it with my master-only cluster:

2.0.0p0 :002 > User.first
 => <User:0x30a1948 _id: 4cddf1ff98db746691000002, display_name: (Deleted account)>
2.0.0p0 :003 > User.with_read_preference(:secondary) { User.first }
Mongo::ConnectionFailure: No replica set member available for query with read preference matching mode secondary and tags matching [].

It works!

If you wanted a setting global to the connection, you could extend the MongoMapper module with a module attribute, and modify the plugin to look for it first, as well.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top