#Updating from mongo ruby drive 1.x to 2.x
We've recently been belatedly migrating to the 2.x series of the mongo ruby driver. At least in part this is because there's very little documentation out there on what has changed, except that there is no backwards compatibility. This post is a list of issues that we came across - I expect it is by no means exhaustive
Before you get started, make sure that any dependencies you have are also comaptible with mongo 2.x. For example database_cleaner
needs to be 1.5 or higher
A lot of the classes / constants in the Mongo::
hierarchy have moved around. For us the lions share were exceptions we were rescuing, for example
Mongo::GridFileNotFound => Mongo::Error::FileNotFound
BSON::InvalidObjectId => BSON::ObjectId::Invalid
Mongo::OperationFailure => Mongo::Error::OperationFailure
Several of the methods here have been renamed or had their signature change slightly.
Previously Collection#find
took a block and yielded a cursor, with the block used to determine the lifetime of the cursor.
find
now returns a view that can be iterated over. If you don't want the cursor to timeout, this option has been renamed from timeout: false
to
no_cursor_timeout: true
The old Mongo::Collection
had an insert
method that took either a single document or an array of documents and inserted them into the collection. You now need to use insert_one
for the single document case and insert_many
for the second case
Previously one of the options the update
method took was a boolean multi:
option that controlled whether mongodb should update all matching documents or only the first one. Instead call update_one
or update_many
Deleting documents used to be via the remove
method, with a limit option to control whether the first matching document was removed or all of them (the default). In 2.x, call delete_one
or delete_many
In 1.x, Mongo::Collection#count
took a single hash of options, which could include a query. In 2.x, the first argument is instead a query. For example
collection.count(query: {active: true}, {read: :secondary})
becomes
collection.count({active: true}, {read: {mode: :secondary}})
This used to look like
grid = Mongo::Grid.new(database)
id = grid.put(data, opts) #data is string or has #read method
grid.get(id) #returns a gridio
In 2.x you would do
grid = database.fs
id = grid.upload_from_stream(filename, io)
grid.open_download_stream(id) do |stream|
stream.each do |chunk| #you can also use stream.get
# do something with data
end
end
Instead of {read: secondary}
, use {read: {mode: :secondary}}
To execute a read against a secondary you can do
collection.with(read: {mode: :secondary}).find(...)
Previously you would do
collection.map_reduce(map_function, reduce_function, {query: {active: true}, ...})
This executes the map reduce operation and, for the inline result types, returns the data
If you wanted to perform that over a subset of the collection, then you added query:
to the options.
In 2.x, map_reduce
is a method on a view and doesn't accept a query option (or rather, it ignores it). The above code would look like
collection.find(active: true).map_reduce(map_function, reduce_function)
This in itself doesn't do anything than create a Mongo::View::MapReduce
object. If you try to iterate over it, that will trigger execution of the map reduce operation. Node that
collection.find(active: true).map_reduce(map_function, reduce_function).map do |value|
...
end
returns the source of the map function, rather than executing Enumerable#map
against the result set (use collect
if you want this)
Like map reduce this now executes lazily. Some options have changed:
allowDiskUse
is nowallow_disk_use
cursor
is nowuse_cursor
The read preference is now set on the collection/view rather than as an option to aggregate, ie
collection.with(:read => { :mode => :secondary }).aggregate(...)