************************* Persistence Configuration ************************* .. default-domain:: mongodb .. contents:: On this page :local: :backlinks: none :depth: 2 :class: singlecol Document Storage ================ Mongoid by default stores documents in a collection that is the pluralized form of the class name. For the following ``Person`` class, the collection the document would get stored in would be named ``people``. .. code-block:: ruby class Person include Mongoid::Document end Model class names cannot end with "s", because it will be considered as the pluralized form of the word. For example "Status" would be considered as the plural form of "Statu", which will cause a few known problems. This is a limitation of the ``ActiveSupport::Inflector#classify`` which Mongoid uses to convert from filenames and collection names to class names. You can overcome this by specifying a custom inflection rule for your model class. For example, the following code will take care of the model named ``Status``. .. code-block:: ruby ActiveSupport::Inflector.inflections do |inflect| inflect.singular("status", "status") end The collection for the model's documents can be changed at the class level if you would like them persisted elsewhere. You can also change the database and client the model gets persisted in from the defaults. .. code-block:: ruby class Person include Mongoid::Document store_in collection: "citizens", database: "other", client: "analytics" end The ``store_in`` macro can also take lambdas - a common case for this is multi-tenant applications. .. code-block:: ruby class Band include Mongoid::Document store_in database: ->{ Thread.current[:database] } end When a document is stored in the database the ruby object will get serialized into BSON and have a structure like so: .. code-block:: ruby { "_id" : ObjectId("4d3ed089fb60ab534684b7e9"), "title" : "Sir", "name" : { "_id" : ObjectId("4d3ed089fb60ab534684b7ff"), "first_name" : "Durran" }, "addresses" : [ { "_id" : ObjectId("4d3ed089fb60ab534684b7e0"), "city" : "Berlin", "country" : "Deutschland" } ] } Persistence Context Attributes ============================== Mongoid provides ``client_name``, ``database_name`` and ``collection_name`` methods on model classes to determine the client, database and collection names used for persistence: .. code-block:: ruby Band.client_name # => :default Band.database_name # => "mongoid" Band.collection_name # => :bands Custom ====== There may be cases where you want to persist documents to different sources from their defaults, or with different options from the default. Mongoid provides run-time support for this as well as support on a per-model basis. Model-Level Persistence Options ------------------------------- On a per-model basis, you can tell it to store in a custom collection name, a different database, or a different client. The following example would store the Band class by default into a collection named "artists" in the database named "music", with the client "analytics". Note that the value supplied to the ``client`` option must be configured under ``clients`` in your mongoid.yml. .. code-block:: ruby class Band include Mongoid::Document store_in collection: "artists", database: "music", client: "analytics" end If no ``store_in`` macro would have been provided, Mongoid would store the model in a collection named "bands" in the default database in the default client. Runtime Persistence Options --------------------------- It is possible to change the client, database and collection, as well as any of the MongoDB client options, used for persistence for a group of operations by using the ``with`` method on a model class or instance: .. code-block:: ruby Band.with(database: "music-non-stop") do |klass| klass.create(...) band = Band.first Band.create(...) end Band.with(collection: "artists") do |klass| klass.delete_all Band.delete_all end band.with(client: :tertiary) do |band_object| band_object.save! band.save! end The ``with`` method creates a temporary persistence context and a MongoDB client to be used for operations in the context. For the duration of the block, the persistence context on the model class or instance that ``with`` was called on is changed to the temporary persistence context. For convenience, the model class or instance that ``with`` was called on is yielded to the block. The temporary persistence context applies to both queries and writes. Care should be taken when performing persistence operations across different persistence contexts. For example, if a document is saved in a temporary persistence context, it may not exist in the default persistence context, failing subsequent updates: .. code-block:: ruby band = Band.new(name: "Scuba") band.with(collection: "artists") do |band_object| band_object.save! end # This will not save - updates the collection "bands" which does not have # the Scuba band band.update_attribute(likes: 1000) # This will update the document. band.with(collection: "artists") do |band_object| band_object.update_attribute(likes: 1000) end As of Mongoid 6.0, the ``with`` method must always be called with a block, and the temporary persistence context exists only for the duration of the block. This is because a new client is created under the covers with the options passed to ``with``. To ensure that this client is closed and its associated resources are freed, the scope when this client could be used must be well-defined. Global Override ``````````````` If you want to switch the persistence context for all operations at runtime, but don't want to be using with all over your code, Mongoid provides the ability to do this as the client and database level globally. The methods for this are ``Mongoid.override_client`` and ``Mongoid.override_database``. A useful case for this are internationalized applications that store information for different locales in different databases or clients, but the schema in each remains the same. .. code-block:: ruby class BandsController < ApplicationController before_action :switch_database after_action :reset_database private def switch_database I18n.locale = params[:locale] || I18n.default_locale Mongoid.override_database("my_db_name_#{I18n.locale}") end def reset_database Mongoid.override_database(nil) end end In the above example, all persistence operations would be stored in the alternative database for all remaining operations on this thread. This is why the after request set the override back to nil - it ensures subsequent requests with no local params use the default option. Persistence context applies to both read and write operations. For example, secondary reads can be performed as follows: .. code-block:: ruby Band.with(read: {mode: :secondary}) do Band.count end Client and Collection Access ---------------------------- If you want to drop down to the driver level to perform operations, you can grab the Mongo client or collection from the model or document instance: .. code-block:: ruby Band.mongo_client band.mongo_client Band.collection band.collection From here you also have the same runtime persistence options using the client's ``#with``: .. code-block:: ruby client = Band.mongo_client.with(write: { w: 0 }, database: "musik") client[:artists].find(...) You can also override the :read or :write options on the collection using the collections ``#with``: .. code-block:: ruby collection_w_0 = Band.collection.with(write: { w: 0 }) collection_w_0[:artists].find(...)