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.