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:
1development:
2 clients:
3 default:
4 database: appsignal_development
5 hosts:
6 - localhost:27017Driver 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:
1 def create_log_entry_collection
2 Mongoid
3 .client('default') # used to be `.session('default')`
4 .with(:read => {:mode => :primary}) # used to be `read: => :primary`
5 .database
6 .command(:create => 'foo')
7 endMoped 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:
1# Before
2Mongoid.client('default')['foo'].insert(document)
3Mongoid.client('default')['foo'].insert([document, document])
4
5# After
6Mongoid.client('default')['foo'].insert_one(document)
7Mongoid.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
_idsort 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:
1# Before
2expect( User.first.name ).to eq 'bob'
3expect( User.last.name ).to eq 'kelso'
4
5# After
6expect( User.asc('_id').first.name ).to eq 'bob'
7expect( User.asc('_id').last.name ).to eq 'kelso'
8
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:
1# concerns/ordered_by_id_asc.rb
2module OrderedByIdAsc
3 extend ActiveSupport::Concern
4
5 included do
6 default_scope -> { asc('_id') }
7 end
8end1# models/account.rb
2class Account
3 include Mongoid::Document
4 include Mongoid::Timestamps
5 include OrderedByIdAsc
6endFindAndModify
Find_and_modify has been removed. Instead you now have 3 methods to chose from:
find_one_and_updatefind_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:
1# Before
2collection.indexes.create_one(
3 {:time => 1},
4 {:expire_after_seconds => ttl}
5)
6
7# After:
8collection.indexes.create_one(
9 {:time => 1},
10 {:expire_after => ttl}
11)
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:
1# Before
2staging:
3 sessions:
4 default:
5 database: appsignal_main
6 username: <%= ENV['MONGOID_USERNAME'] %>
7 password: <%= ENV['MONGOID_PASSWORD'] %>
8 hosts:
9 - mongo1.staging:27017
10 - mongo2.staging:27017
11 - mongo3.staging:27017
12 options:
13 read: :primary
14 pool_size: {{ mongoid_pool_size }}
15 ssl:
16 ca_file: /etc/ssl/certs/root_ca.crt
17 client_cert: /app/shared/config/mongodb_app.crt
18 client_key: /app/shared/config/mongodb_app.key
19
20# After
21staging:
22 clients:
23 default:
24 database: appsignal_main
25 hosts:
26 - mongo1.staging:27017
27 - mongo2.staging:27017
28 - mongo3.staging:27017
29 options:
30 user: <%= ENV['MONGOID_USERNAME'] %>
31 password: <%= ENV['MONGOID_PASSWORD'] %>
32 read:
33 mode: :primary
34 max_pool_size: {{ mongoid_pool_size }}
35 ssl: true
36 ssl_ca_cert: /etc/ssl/certs/root_ca.crt
37 ssl_cert: /app/shared/config/mongodb_app.crt
38 ssl_key: /app/shared/config/mongodb_app.key
39 replica_set: stagingusernamehas been renamed touserand moved tooptionspasswordhas been moved tooptionsreadnow expects a nested key namedmodeSSLis no longer a nested hash, but is set underoptions- The config requires a
replica_setkey 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.