What's New
On this page
Learn what's new in:
To view a list of releases and detailed release notes, see Mongoid Releases on GitHub.
What's New in 9.0
The 9.0 release includes the following new features, improvements, and fixes:
Railsmdb
Alongside the release of Mongoid v9.0, railsmdb
, a command-line utility
for creating, updating, managing, and maintaining Rails applications, is
generally available.
railsmdb
makes it easier to work with MongoDB from the command line
through common generators that Ruby on Rails developers are already
familiar with.
For example, you can use railsmdb
to generate stubs for new Mongoid models:
bin/railsmdb generate model person
This will create a new model at app/models/person.rb
:
class Person include Mongoid::Document include Mongoid::Timestamp end
You can specify the fields of the model:
bin/railsmdb generate model person name:string birth:date
class Person include Mongoid::Document include Mongoid::Timestamp field :name, type: String field :birth, type: Date end
You can instruct the generator to make the new model a subclass of another,
by passing the --parent
option:
bin/railsmdb generate model student --parent=person
class Student < Person include Mongoid::Timestamp end
If you need to store your models in a different collection than can be
inferred from the model name, you can specify --collection
:
bin/railsmdb generate model course --collection=classes
class Course include Mongoid::Document include Mongoid::Timestamp store_in collection: 'classes' end
For more information see the mongoid-railsmdb repository on GitHub.
Removal of Support for Ruby 2.6 and JRuby 9.3
Mongoid v9.0 requires Ruby 2.7 or newer or JRuby 9.4. Earlier Ruby and JRuby versions are not supported.
Removal of Support for Rails 5
Mongoid v9.0 requires Rails 6.0 or newer. Earlier Rails versions are not supported.
Removal of Deprecated Class Mongoid::Errors::InvalidStorageParent
The deprecated class Mongoid::Errors::InvalidStorageParent
has been
removed.
around_*
Callbacks for Embedded Documents are Ignored
Mongoid v8.x and older allow user to define around_*
callbacks for embedded
documents. Starting in v9.0, these callbacks are ignored and will not be executed.
A warning will be printed to the console if such callbacks are defined.
If you want to restore the old behavior, you can set
Mongoid.around_embedded_document_callbacks
to true in your application.
Note
Enabling around_*
callbacks for embedded documents is not recommended
as it may cause SystemStackError
exceptions when a document has many
embedded documents. See MONGOID-5658 for more details.
for_js
Method is Deprecated
The for_js
method is deprecated and will be removed in Mongoid v10.0.
Removal of Deprecated Options
Breaking change: The following config options are removed in Mongoid v9.0.
Please ensure you have removed all references to these from your app.
If you were using config.load_defaults 8.1
before upgrading, you will not
experience any behavior change. Refer to earlier release notes for the meaning
of each option.
:use_activesupport_time_zone
:broken_aggregables
:broken_alias_handling
:broken_and
:broken_scoping
:broken_updates
:compare_time_by_ms
:legacy_attributes
:legacy_pluck_distinct
:legacy_triple_equals
:object_id_as_json_oid
:overwrite_chained_operators
In addition, support for config.load_defaults
versions v7.5 and
prior has been dropped (you must use a minimum of version v8.0.)
Removal of Deprecated Functionality
Breaking change: The following deprecated functionality is now removed:
The
Mongoid::QueryCache
module has been removed. Please replace any usages 1-for-1 withMongo::QueryCache
. The methodMongoid::QueryCache#clear_cache
should be replaced withMongo::QueryCache#clear
. All other methods and submodules are identically named.Object#blank_criteria?
method is removed (previously deprecated).Document#as_json :compact
option is removed. Please call`#compact
on the returnedHash
object instead.The deprecated class
Mongoid::Errors::InvalidStorageParent
has been removed.
touch
Method Clears Changed State
In Mongoid v8.x and older, the touch
method leaves models in the
changed state:
# v8.x behaviour band = Band.create! band.touch band.changed? # => true band.changes # => {"updated_at"=>[2023-01-30 13:12:57.477191135 UTC, 2023-01-30 13:13:11.482975646 UTC]}
Starting in v9.0, Mongoid now correctly clears changed state after using
the touch
method.
# v9.0 behavior band = Band.create! band.touch band.changed? # => false band.changes # => {}
Sandbox Mode for Rails Console
Mongoid now supports Rails console sandbox mode. If the Rails console started
with --sandbox
flag, Mongoid starts a transaction on the :default
client
before opening the console. This transaction won't be committed. Therefore, all
the commands executed in the console using the :default
client won't
be persisted in the database.
Note
If you execute commands in the sandbox mode using any other client than default, these changes will be persisted as usual.
New Transactions API
Mongoid 9.0 introduces new transactions API that is inspired by Active Record:
Band.transaction do Band.create(title: 'Led Zeppelin') end band = Band.create(title: 'Deep Purple') band.transaction do band.active = false band.save! end
To learn more, see the Transactions and Sessions guide.
Embedded Documents Always Use Parent Persistence Context
Mongoid v8.x and older allow user to specify persistence context for an
embedded document (using store_in
macro). In Mongoid v9.0 these settings are
ignored for embedded documents. An embedded document now always uses the persistence
context of its parent.
Support for Passing Raw Values into Queries
When performing queries, it is now possible to skip Mongoid's type coercion logic
by using the Mongoid::RawValue
wrapper class. This can be useful when legacy
data in the database is of a different type than the field definition.
class Person include Mongoid::Document field :age, type: Integer end # Query for the string "42", not the integer 42 Person.where(age: Mongoid::RawValue("42"))
Raise AttributeNotLoaded
Error When Accessing Fields Omitted from Query Projection
When attempting to access a field on a model instance which was
excluded with the only
or without
query projections methods
when the instance was loaded, Mongoid will now raise a
Mongoid::Errors::AttributeNotLoaded
error.
Band.only(:name).first.label #=> raises Mongoid::Errors::AttributeNotLoaded Band.without(:label).first.label = 'Sub Pop Records' #=> raises Mongoid::Errors::AttributeNotLoaded
In earlier Mongoid versions, the same conditions would raise an
ActiveModel::MissingAttributeError
. Please check your code for
any Mongoid-specific usages of this class, and change them to
Mongoid::Errors::AttributeNotLoaded
. Note additionally that
AttributeNotLoaded
inherits from Mongoid::Errors::MongoidError
,
while ActiveModel::MissingAttributeError
does not.
Use Configured Time Zone to Typecast Date
to Time
in Queries
When querying for a Time field using a Date value, Mongoid now correctly
considers Time.zone
to perform type conversion.
class Magazine include Mongoid::Document field :published_at, type: Time end Time.zone = 'Asia/Tokyo' Magazine.gte(published_at: Date.parse('2022-09-26')) #=> will return all results on or after Sept 26th, 2022 # at 0:00 in Asia/Tokyo time zone.
In prior Mongoid versions, the above code would ignore the Time.zone
(irrespective of the now-removed :use_activesupport_time_zone
setting) and would always use the system time zone to perform the type
conversion.
Note that in prior Mongoid versions, typecasting Date
to Time
during persistence operations was already correctly using time zone.
touch
Method on Embedded Documents Correctly Handles touch: false
Option
When the touch: false
option is set on an embedded_in
relation,
calling the touch
method on an embedded child document will not
invoke touch
on its parent document.
class Address include Mongoid::Document include Mongoid::Timestamps embedded_in :mall, touch: false end class Mall include Mongoid::Document include Mongoid::Timestamps embeds_many :addresses end mall = Mall.create! address = mall.addresses.create! address.touch #=> updates address.updated_at but not mall.updated_at
In addition, the touch
method has been optimized to perform one
persistence operation per parent document, even when using multiple
levels of nested embedded documents.
embedded_in
Associations Default to touch: true
Updating an embedded sub-document will now automatically touch the
parent, unless you explicitly set touch: false
on the relation:
class Address include Mongoid::Document include Mongoid::Timestamps embedded_in :mall, touch: false end
For all other associations, the default remains touch: false
.
Flipped Default for :replace
Option in upsert
Mongoid v8.1 added the :replace
option to the upsert
method. This
option was used to specify whether or not the existing document should be
updated or replaced.
Mongoid v9.0 flips the default of this flag from true
to false
.
This means that, by default, Mongoid v9.0 updates the existing document and
does not replace it.
Immutability of the _id
Field Enforced
Before Mongoid v9.0, mutating the _id
field behaved inconsistently
depending on whether the document was top-level or embedded, and depending on
how the update was performed. In v9.0, changing the _id
field will now
raise an exception when the document is saved, if the document had been
previously persisted.
Mongoid 9.0 also introduces a new feature flag, immutable_ids
, which
defaults to true
.
Mongoid::Config.immutable_ids = true
When set to false
, the older, inconsistent behavior is restored.
Support for Field Aliases on Index Options
Support has been added to use aliased field names in the following options
of the index
macro: partial_filter_expression
, weights
,
wildcard_projection
.
class Person include Mongoid::Document field :a, as: :age index({ age: 1 }, { partial_filter_expression: { age: { '$gte' => 20 } }) end
Note
The expansion of field name aliases in index options such as
partial_filter_expression
is performed according to the behavior of MongoDB
server 6.0. Future server versions may change how they interpret these options,
and Mongoid's functionality may not support such changes.
BSON 5 and BSON::Decimal128
Fields
When BSON 4 or earlier is present, any field declared as BSON::Decimal128
will
return a BSON::Decimal128
value. When BSON 5 is present, however, any field
declared as BSON::Decimal128
will return a BigDecimal
value by default.
class Model include Mongoid::Document field :decimal_field, type: BSON::Decimal128 end # under BSON <= 4 Model.first.decimal_field.class #=> BSON::Decimal128 # under BSON >= 5 Model.first.decimal_field.class #=> BigDecimal
If you need literal BSON::Decimal128
values with BSON 5, you may instruct
Mongoid to allow literal BSON::Decimal128
fields:
Model.first.decimal_field.class #=> BigDecimal Mongoid.allow_bson5_decimal128 = true Model.first.decimal_field.class #=> BSON::Decimal128
Note
The allow_bson5_decimal128
option only has any effect under
BSON 5 and later. BSON 4 and earlier ignore the setting entirely.
Search Index Management for MongoDB Atlas
When connected to MongoDB Atlas, Mongoid now supports creating and removing
search indexes. You may do so programmatically, via the Mongoid::SearchIndexable
API:
class SearchablePerson include Mongoid::Document search_index { ... } # define the search index here end # create the declared search indexes; this returns immediately, but the # search indexes may take several minutes before they are available. SearchablePerson.create_search_indexes # query the available search indexes SearchablePerson.search_indexes.each do |index| # ... end # remove all search indexes from the model's collection SearchablePerson.remove_search_indexes
If you are not connected to MongoDB Atlas, the search index definitions are ignored. Trying to create, enumerate, or remove search indexes will result in an error.
There are also rake tasks available, for convenience:
# create search indexes for all models; waits for indexes to be created # and shows progress on the terminal. $ rake mongoid:db:create_search_indexes # as above, but returns immediately and lets the indexes be created in the # background $ rake WAIT_FOR_SEARCH_INDEXES=0 mongoid:db:create_search_indexes # removes search indexes from all models $ rake mongoid:db:remove_search_indexes
Removal of Time.configured
Time.configured
returned either the time object wrapping the configured
time zone, or the standard Ruby Time
class. This allowed you to query
a time value even if no time zone had been configured.
Mongoid now requires that you set a time zone if you intend to do
anything with time values (including using timestamps in your documents).
Any uses of Time.configured
must be replaced with Time.zone
.
# before: puts Time.configured.now # after: puts Time.zone.now # or, better for finding the current Time specifically: puts Time.current
If you do not set a time zone, you will see errors in your code related
to nil
values. If you are using Rails, the default time zone is already
set to UTC. If you are not using Rails, you may set a time zone at the start
of your program like this:
Time.zone = 'UTC'
This will set the time zone to UTC. You can see all available time zone names by running the following command:
$ ruby -ractive_support/values/time_zone \ -e 'puts ActiveSupport::TimeZone::MAPPING.keys'
Records Remember Persistence Context of Creation
Consider the following code:
record = Model.with(collection: 'other_collection') { Model.first } record.update(field: 'value')
Before Mongoid v9.0, the preceding code silently fails to execute the update,
because the storage options (here, the specification of an alternate
collection for the model) would not be remembered by the record. Thus, the
record would be loaded from other_collection
, but when updated, would attempt
to look for and update the document in the default collection for Model. To
make this work, you would have had to specify the collection explicitly for
every update.
As of Mongoid v9.0, records that are created or loaded under explicit storage options, will remember those options (including a named client, a different database, or a different collection).
If you need the legacy (pre-v9.0) behavior, you can enable it with the following flag:
Mongoid.legacy_persistence_context_behavior = true
This flag defaults to false in Mongoid v9.0.