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: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:
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 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:
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
_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
:
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
8end
1# models/account.rb
2class Account
3 include Mongoid::Document
4 include Mongoid::Timestamps
5 include OrderedByIdAsc
6end
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
:
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: 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.