Upgrading to Mongoid 5 / mongo-ruby-driver
source link: https://blog.appsignal.com/2016/03/21/upgrading-mongoid.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Development configuration
One of the first things you’ll encounter when starting your Rails app after upgrading to Mongoid 5 is an error about your database config being incorrect.
The fix is easy, just change sessions
to clients
:
development: clients: default: database: appsignal_development hosts: - localhost:27017
Driver changes
In our codebase we “drop down to the driver” a lot to execute queries directly on moped/mongo-ruby-driver, instead of using Mongoid, e.g. to create collections for each account. Here you’ll also need to change session
to client
.
Another change is that read
now expects a hash with a :mode
key, instead of the value directly:
def create_log_entry_collection Mongoid .client('default') # used to be `.session('default')` .with(:read => {:mode => :primary}) # used to be `read: => :primary` .database .command(:create => 'foo') end
Moped has an insert
method that accepts either a single document or an array of documents. The new mongo-ruby-driver comes with two separate methods, and you should pick one depending on the amount of documents you’d like to insert:
# Before Mongoid.client('default')['foo'].insert(document) Mongoid.client('default')['foo'].insert([document, document]) # After Mongoid.client('default')['foo'].insert_one(document) Mongoid.client('default')['foo'].insert_many([document, document])
Lack of ordering
One of the biggest changes with the new driver is that documents are no longer ordered on _id
by default.
First and last no longer add an
_id
sort when no sorting options have been provided. In order to guarantee that a document is the first or last, it needs to now contain an explicit sort.
This means that anywhere where you rely on ordering (.first
, .last
) you need to explicitly order the query by _id
:
# Before expect( User.first.name ).to eq 'bob' expect( User.last.name ).to eq 'kelso' # After expect( User.asc('_id').first.name ).to eq 'bob' expect( User.asc('_id').last.name ).to eq 'kelso'
In order to make sure our code behaves as it used to, we created a concern that adds a default scope that orders by _id
:
# concerns/ordered_by_id_asc.rb module OrderedByIdAsc extend ActiveSupport::Concern included do default_scope -> { asc('_id') } end end
# models/account.rb class Account include Mongoid::Document include Mongoid::Timestamps include OrderedByIdAsc end
FindAndModify
Find_and_modify
has been removed. Instead you now have 3 methods to chose from:
find_one_and_update
find_one_and_replace
(Convenience method, callsfind_one_and_update
)find_one_and_delete
ExpireAfterSeconds
One of the more obscure changes is the way a TTL index is created. We use TTL indexes to automatically purge customer data depending on their plan (e.g. after 7 days, or after a month).
The option on the index used to be called expire_after_seconds
, but has been renamed to expire_after
:
# Before collection.indexes.create_one( {:time => 1}, {:expire_after_seconds => ttl} ) # After: collection.indexes.create_one( {:time => 1}, {:expire_after => ttl} )
Staging/Production config changes
While in development we only needed to change sessions
to clients
, but our staging/production configs needed a lot more work:
# Before staging: sessions: default: database: appsignal_main username: <%= ENV['MONGOID_USERNAME'] %> password: <%= ENV['MONGOID_PASSWORD'] %> hosts: - mongo1.staging:27017 - mongo2.staging:27017 - mongo3.staging:27017 options: read: :primary pool_size: {{ mongoid_pool_size }} ssl: ca_file: /etc/ssl/certs/root_ca.crt client_cert: /app/shared/config/mongodb_app.crt client_key: /app/shared/config/mongodb_app.key # After staging: clients: default: database: appsignal_main hosts: - mongo1.staging:27017 - mongo2.staging:27017 - mongo3.staging:27017 options: user: <%= ENV['MONGOID_USERNAME'] %> password: <%= ENV['MONGOID_PASSWORD'] %> read: mode: :primary max_pool_size: {{ mongoid_pool_size }} ssl: true ssl_ca_cert: /etc/ssl/certs/root_ca.crt ssl_cert: /app/shared/config/mongodb_app.crt ssl_key: /app/shared/config/mongodb_app.key replica_set: staging
username
has been renamed touser
and moved tooptions
password
has been moved tooptions
read
now expects a nested key namedmode
SSL
is no longer a nested hash, but is set underoptions
- The config requires a
replica_set
key if the setup is a replicaset
The upgrade documentation says that MongoDB 2.4 and 2.6 use :plain
auth, but we needed to remove the auth_mech
key all together for the setup to work.
Conclusion
Although this is quite an extensive list, we found the upgrade to be relatively painless and the new driver feels a lot more solid than the old Moped driver.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK