diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index e35d8850c9..0000000000 --- a/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_build diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index d4bb2cbb9e..0000000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index a3e415face..0000000000 --- a/docs/README.md +++ /dev/null @@ -1,14 +0,0 @@ -Mongoid Documentation -================================= - -This subdirectory contains the high-level driver documentation, including -tutorials and the reference. - -To build the documentation locally for review, install `sphinx` and -`sphinx-book-theme`, then execute `make html` in this directory: - - pip install 'sphinx<4.3' sphinx-book-theme - make html - -Note: sphinx 4.3 is currently breaking when trying to render Mongoid -documentation. diff --git a/docs/additional-resources.txt b/docs/additional-resources.txt deleted file mode 100644 index 8de82da599..0000000000 --- a/docs/additional-resources.txt +++ /dev/null @@ -1,61 +0,0 @@ -******************** -Additional Resources -******************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -This page lists some of the third-party guides and blog posts about Mongoid, -as well as sample Mongoid applications. Additional resources for the driver -are listed on the `respective driver page -`_. - - -Screencasts -=========== - -- `RailsCasts: Mongoid (revised) - `_ - - An overview of Mongoid, by Ryan Bates including the basics - of setting up an app, querying for documents, adding embedded - associations, overriding the id, and more. - -- `Ruby on Rails Web Services and Integration with MongoDB, Week 3: Mongoid - `_ - - A detailed introduction to Mongoid and Ruby on Rails web services. - -- `Create a search bar in Rails with Mongoid - `_ - - A Tutorial explaining how to implement text search with Mongoid. - - -Articles -======== - -- `A Simple Content Management System in Sinatra `_ - - Building a content management application with Sinatra and Mongoid. - -- `How To Create A Ruby API With Sinatra `_ - - Creating a Sinatra API with Mongoid. - -- `Converting an existing Ruby on Rails application to MongoDB `_ - - How to Convert an existing Ruby on Rails application to use MongoDB and Mongoid. - - -Sample Applications -=================== - -- `Mongoid Demo `_ - - A repository containing sample applications using Mongoid. diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index b634583a1a..0000000000 --- a/docs/conf.py +++ /dev/null @@ -1,57 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - -# -- Project information ----------------------------------------------------- - -project = 'Mongoid' -copyright = '2021, MongoDB' - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -source_suffix = { - '.txt': 'restructuredtext', -} - -html_theme = 'sphinx_book_theme' diff --git a/docs/contributing.txt b/docs/contributing.txt deleted file mode 100644 index abb7d73714..0000000000 --- a/docs/contributing.txt +++ /dev/null @@ -1,21 +0,0 @@ -.. _contributing: - -************ -Contributing -************ - -.. default-domain:: mongodb - -.. toctree:: - :titlesonly: - - contributing/code-documentation - contributing/contributing-guidelines - -Overview --------- - -Learn how to contribute to the Mongoid repository in the following sections: - -- :ref:`Code Documentation ` -- :ref:`Contributing Guidelines ` \ No newline at end of file diff --git a/docs/contributing/code-documentation.txt b/docs/contributing/code-documentation.txt deleted file mode 100644 index 9713ce278a..0000000000 --- a/docs/contributing/code-documentation.txt +++ /dev/null @@ -1,353 +0,0 @@ -.. _code-documentation: - -****************** -Code Documentation -****************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -Code Documentation -================== - -Mongoid uses its own flavor of `YARD `_ -for code documentation. Please note the conventions outlined in this document. - - -.. _code-documentation-structure: - -Structure ---------- - -- **Modules:** All class and module definitions should be preceded by - a documentation comment. - - .. code-block:: ruby - - # This is the documentation for the class. It's amazing - # what they do with corrugated cardboard these days. - class CardboardBox - -- **Methods:** All method definitions should be preceded by a documentation comment. - Use ``@param``, ``@yield``, and ``@return`` to specify inputs and output. - For further details, refer to - :ref:`Type Declaration ` below. - - .. code-block:: ruby - - # Turn a person into whatever they'd like to be. - # - # @param [ Person ] person The human to transmogrify. - # - # @return [ Tiger ] The transmogrified result. - def transmogrify(person) - -- **Errors:** Use ``@raise`` to explain errors specific to the method. - - .. code-block:: ruby - - # @raise [ Errors::Validations ] If validation failed. - def validate! - -- **Private Methods:** Private methods should be documented unless they are - so brief and straightforward that it is obvious what they do. Note that, - for example, a method may be brief and straightforward but the type of - its parameter may not be obvious, in which case the parameter must be - appropriately documented. - - .. code-block:: ruby - - private - - # Documentation is optional here. - def do_something_obvious - -- **API Private:** Classes and public methods which are not intended for - external usage should be marked ``@api private``. This macro does not - require a comment. - - Note that, because Mongoid's modules are mixed into application classes, - ``private`` visibility of a method does not necessarily indicate its - status as an API private method. - - .. code-block:: ruby - - # This is an internal-only method. - # - # @api private - def dont_call_me_from_outside - -- **Notes and TODOs:** Use ``@note`` to explain caveats, edge cases, - and behavior which may surprise users. Use ``@todo`` to record - follow-ups and suggestions for future improvement. - - .. code-block:: ruby - - # Clear all stored data. - # - # @note This operation deletes data in the database. - # @todo Refactor this method for performance. - def erase_data! - -- **Deprecation:** Use the ``@deprecated`` macro to indicate deprecated - functionality. This macro does not require a comment. - - .. code-block:: ruby - - # This is how we did things back in the day. - # - # @deprecated - def the_old_way - - -.. _code-documentation-formatting: - -Formatting ----------- - -- **Line Wrapping:** Use double-space indent when wrapping lines of macros. - Do not indent line wraps in the description. - - .. code-block:: ruby - - # This is the description of the method. Line wraps in the description - # should not be indented. - # - # @return [ Symbol ] For macros, wraps must be double-space indented - # on the second, third, etc. lines. - -- **Whitespace:** Do not use leading/trailing empty comment lines, - or more than one consecutive empty comment line. - - .. code-block:: ruby - - # GOOD: - # @return [ Symbol ] The return value - def my_method - - # BAD: - # @return [ Symbol ] The return value - # - def my_method - - # BAD: - # @param [ Symbol ] foo The input value - # - # - # @return [ Symbol ] The return value - def my_method(foo) - - -.. _code-documentation-type-declaration: - -Type Declaration ----------------- - -- **Type Unions:** Use pipe ``|`` to denote a union of allowed types. - - .. code-block:: ruby - - # @param [ Symbol | String ] name Either a Symbol or a String. - -- **Nested Types:** Use angle brackets ``< >`` to denote type nesting. - - .. code-block:: ruby - - # @param [ Array ] array An Array of symbols. - -- **Hash:** Use comma ``,`` to denote the key and value types. - - .. code-block:: ruby - - # @param [ Hash ] hash A Hash whose keys are Symbols, - # and whose values are Integers. - -- **Array:** Use pipe ``|`` to denote a union of allowed types. - - .. code-block:: ruby - - # @param [ Array ] array An Array whose members must - # be either Symbols or Strings. - -- **Array:** Use comma ``,`` to denote the types of each position in a tuple. - - .. code-block:: ruby - - # @return [ Array ] A 3-member Array whose first - # element is a Symbol, and whose second and third elements are Integers. - -- **Array:** Use pipe ``|`` on the top level if the inner types cannot be - mixed within the Array. - - .. code-block:: ruby - - # @param [ Array | Array ] array An Array containing only - # Symbols, or an Array containing only Hashes. The Array may not contain - # a mix of Symbols and Hashes. - -- **Nested Types:** For clarity, use square brackets ``[ ]`` to denote nested unions - when commas are also used. - - .. code-block:: ruby - - # @param [ Hash ] hash A Hash whose keys are Symbols, - # and whose values are boolean values. - -- **Ruby Values:** Specific values may be denoted in the type using Ruby syntax. - - .. code-block:: ruby - - # @param [ :before | :after ] timing One of the Symbol values :before or :after. - -- **True, False, and Nil:** Use ``true``, ``false``, and ``nil`` rather than - ``TrueClass``, ``FalseClass``, and ``NilClass``. Do not use ``Boolean`` as a type - since it does not exist in Ruby. - - .. code-block:: ruby - - # GOOD: - # @param [ true | false | nil ] bool A boolean or nil value. - - # BAD: - # @param [ TrueClass | FalseClass | NilClass ] bool A boolean or nil value. - # @param [ Boolean ] bool A boolean value. - -- **Return Self:** Specify return value ``self`` where a method returns ``self``. - - .. code-block:: ruby - - # @return [ self ] Returns the object itself. - -- **Splat Args:** Use three-dot ellipses ``...`` in the type declaration and - star ``*`` in the parameter name to denote a splat. - - .. code-block:: ruby - - # @param [ String... ] *items The list of items name(s) as Strings. - def buy_groceries(*items) - -- **Splat Args:** Do not use ``Array`` as the type unless each arg is actually an Array. - - .. code-block:: ruby - - # BAD: - # @param [ Array ] *items The list of items name(s) as Strings. - def buy_groceries(*items) - - buy_groceries("Cheese", "Crackers", "Wine") - - # OK: - # @param [ Array... ] *arrays One or more arrays containing name parts. - def set_people_names(*arrays) - - set_people_names(["Harlan", "Sanders"], ["Jane", "K", ""Doe"], ["Jim", "Beam"]) - -- **Splat Args:** Use comma ``,`` to denote positionality in a splat. - - .. code-block:: ruby - - # @param [ Symbol..., Hash ] *args A list of names, followed by a hash - # as the optional last arg. - def say_hello(*args) - -- **Splat Args:** Specify type unions with square brackets ``[ ]``. - - .. code-block:: ruby - - # @param [ [ String | Symbol ]... ] *fields A splat of mixed Symbols and Strings. - -- **Keyword Arguments:** Following YARD conventions, use ``@param`` for keyword - arguments, and specify keyword argument names as symbols. - - .. code-block:: ruby - - # @param [ String ] query The search string - # @param [ Boolean ] :exact_match Whether to do an exact match - # @param [ Integer ] :results_per_page Number of results - def search(query, exact_match: false, results_per_page: 10) - -- **Hash Options:** Define hash key-value options with ``@option`` macro - immediately following the Hash ``@param``. Note ``@option`` parameter names - are symbols. - - .. code-block:: ruby - - # @param opts [ Hash ] The optional hash argument(s). - # @option opts [ String | Array ] :items The items(s) as Strings to include. - # @option opts [ Integer ] :limit An Integer denoting the limit. - def buy_groceries(opts = {}) - -- **Double Splats:** Use double-star ``**`` in the parameter name to denote a - keyword arg splat (double splat). Note that type does not need declared on - the double-splat element, as it is implicitly . Instead, - define value types with ``@option`` macro below. Note ``@option`` parameter - names are symbols. - - .. code-block:: ruby - - # @param **kwargs The optional keyword argument(s). - # @option **kwargs [ String | Array ] :items The items(s) as Strings to include. - # @option **kwargs [ Integer ] :limit An Integer denoting the limit. - def buy_groceries(**kwargs) - -- **Blocks:** Use ``@yield`` to specify when the method yields to a block. - - .. code-block:: ruby - - # @yield [ Symbol, Symbol, Symbol ] Evaluate the guess of who did the crime. - # Must take the person, location, and weapon used. Must return true or false. - def whodunit - yield(:mustard, :ballroom, :candlestick) - end - -- **Blocks:** If the method explicitly specifies a block argument, specify the block - argument using ``@param`` preceded by an ampersand ``&``, and also specify ``@yield``. - Note ``@yield`` should be used even when method calls ``block.call`` rather than - ``yield`` internally. - - .. code-block:: ruby - - # @param &block The block. - # @yield [ Symbol, Symbol, Symbol ] Evaluate the guess of who did the crime. - # Must take the person, location, and weapon used. Must return true or false. - def whodunit(&block) - yield(:scarlet, :library, :rope) - end - - # @param &block The block. - # @yield [ Symbol, Symbol, Symbol ] Evaluate the guess of who did the crime. - # Must take the person, location, and weapon used. Must return true or false. - def whodunit(&block) - block.call(:plum, :kitchen, :pipe) - end - -- **Blocks:** Use ``@yieldparam`` and ``@yieldreturn`` instead of ``@yield`` where - beneficial for clarity. - - .. code-block:: ruby - - # @param &block The block. - # @yieldparam [ Symbol ] The person. - # @yieldparam [ Symbol ] The location. - # @yieldparam [ Symbol ] The weapon used. - # @yieldreturn [ true | false ] Whether the guess is correct. - def whodunit(&block) - yield(:peacock, :conservatory, :wrench) - end - -- **Proc Args:** Proc arguments should use ``@param`` (not ``@yield``). The - inputs to the proc may be specified as subtype(s). - - .. code-block:: ruby - - # @param [ Proc ] my_proc Proc argument which must - # take 3 integers and must return true or false whether the guess is valid. - def guess_three(my_proc) - my_proc.call(42, 7, 88) - end diff --git a/docs/contributing/contributing-guidelines.txt b/docs/contributing/contributing-guidelines.txt deleted file mode 100644 index 68491bd5b2..0000000000 --- a/docs/contributing/contributing-guidelines.txt +++ /dev/null @@ -1,43 +0,0 @@ -.. _contributing-guidelines: - -*********************** -Contributing Guidelines -*********************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -Contributing Guidelines -======================= - -If you wish to propose an enhancement to Mongoid, please create a Jira ticket -describing the enhancement and what it would enable you to achieve in your -application that is not already possible. If you believe Mongoid is not -behaving correctly, please create a Jira ticket describing how you use Mongoid, -what the existing behavior is that you consider incorrect or problematic, and -what your desired behavior is. If you wish to make changes yourself, the -following guildelines should be followed: - -#. Create a fork of Mongoid. -#. Create a new branch in that fork. -#. Make your changes. -#. Ensure that the proposed changes have adequate test coverage. -#. Raise a PR against Mongoid master. If these changes correspond to a specific - Jira ticket, title the PR: "MONGOID- Description of Changes". -#. The Mongoid team will review the PR and make comments/suggest changes. -#. Once all of the changes and fixes are made, and the Mongoid team determine - the PR fit for merging, we will merge the PR into master and determine - whether it needs to be backported. -#. Backports to previous stable versions are done if the change is a bug fix, - is not backwards breaking, and if the commit is applicable to the - corresponding stable branch. Presently backport candidates would include - versions 7.3-8.0. -#. Changes to 6.0-7.2 are generally not made unless it fixes a security - vulnerability. -#. 5.x and earlier is generally not supported. \ No newline at end of file diff --git a/docs/ecosystem.txt b/docs/ecosystem.txt deleted file mode 100644 index a754c45ec4..0000000000 --- a/docs/ecosystem.txt +++ /dev/null @@ -1,84 +0,0 @@ -********* -Ecosystem -********* - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Mongoid has an extensive ecosystem of libraries integrating with or built -on top of Mongoid, are listed below. - - -Projects -======== - -- `Workarea Commerce `_ - - Workarea is an enterprise-grade Ruby on Rails commerce platform that uses Mongoid. - - -Extension Libraries -=================== - -- `Mongoid Tree `_ - - A tree structure for Mongoid documents using the materialized path pattern. - -- `Mongoid Token `_ - - A little random, unique token generator for Mongoid documents. - -- `Mongoid Collection Snapshot `_ - - Easy maintenance of collections of processed data in MongoDB with the Mongoid ODM. - -- `Mongoid Locker `_ - - Document-level locking for MongoDB via Mongoid. - -- `Mongo Beautiful Logger `_ - - A simple and beautiful logger library for MongoDB in your Ruby/Rails app. - -- `Mongoid Search `_ - - Simple full text search for Mongoid. - -- `Mongoid Fulltext Search `_ - - Full-text search using n-gram matching for the Mongoid ODM. - - -Integration Libraries -===================== - -- `CarrierWave Mongoid `_ - - Mongoid Support for the Carrierwave file uploads library. - -- `Mongoid RSpec `_ - - RSpec matchers and macros for Mongoid applications. - -- `RailsAdmin `_ supports Mongoid out - of the box. - -- `ActiveAdmin Mongoid `_ - - ActiveAdmin hacks to support Mongoid. - -- `Mongoid History `_ - - Multi-user non-linear history tracking, auditing, undo, redo for mongoid. -- `Delayed Job Mongoid `_ - - Mongoid backend for delayed_job. - -- `Mongo Session Store `_ - - A Rails-compatible session store for Mongoid. diff --git a/docs/img/rails-blog-new-comment.png b/docs/img/rails-blog-new-comment.png deleted file mode 100644 index f82a56e9f6..0000000000 Binary files a/docs/img/rails-blog-new-comment.png and /dev/null differ diff --git a/docs/img/rails-new-blog.png b/docs/img/rails-new-blog.png deleted file mode 100644 index 210355a261..0000000000 Binary files a/docs/img/rails-new-blog.png and /dev/null differ diff --git a/docs/includes/unicode-ballot-x.rst b/docs/includes/unicode-ballot-x.rst deleted file mode 100644 index 50c3667ae6..0000000000 --- a/docs/includes/unicode-ballot-x.rst +++ /dev/null @@ -1 +0,0 @@ -.. |x| unicode:: U+2717 diff --git a/docs/includes/unicode-checkmark.rst b/docs/includes/unicode-checkmark.rst deleted file mode 100644 index 16f4e94764..0000000000 --- a/docs/includes/unicode-checkmark.rst +++ /dev/null @@ -1 +0,0 @@ -.. |checkmark| unicode:: U+2713 diff --git a/docs/index.txt b/docs/index.txt deleted file mode 100644 index 0f320dd552..0000000000 --- a/docs/index.txt +++ /dev/null @@ -1,24 +0,0 @@ -.. _mongoid: - -******* -Mongoid -******* - -.. default-domain:: mongodb - -Mongoid is the officially supported object-document mapper (ODM) for MongoDB in -Ruby. To work with Mongoid from the command line using ``rails``-like tooling, -the `railsmdb `_ utility can be used. - -.. toctree:: - :titlesonly: - - installation-configuration - tutorials - schema-configuration - working-with-data - API - release-notes - contributing - additional-resources - ecosystem diff --git a/docs/installation-configuration.txt b/docs/installation-configuration.txt deleted file mode 100644 index fd5ea05b3a..0000000000 --- a/docs/installation-configuration.txt +++ /dev/null @@ -1,25 +0,0 @@ -.. _installation-configuration: - -**************************** -Installation & Configuration -**************************** - -.. default-domain:: mongodb - -.. toctree:: - :titlesonly: - - installation - reference/compatibility - reference/configuration - reference/rails-integration - -Overview --------- - -Learn how to install and configure Mongoid in the following sections: - -- :ref:`Installation ` -- :ref:`Compatibility ` -- :ref:`Configuration ` -- :ref:`Rails Integration ` \ No newline at end of file diff --git a/docs/installation.txt b/docs/installation.txt deleted file mode 100644 index bd9e290890..0000000000 --- a/docs/installation.txt +++ /dev/null @@ -1,66 +0,0 @@ -.. _installation: - -************ -Installation -************ - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Install the Gem -=============== - -Mongoid is bundled as a gem, and is `hosted on Rubygems -`_. -It can be installed manually or with bundler. - -To install the gem manually: - -.. code-block:: sh - - gem install mongoid - -To install the gem with bundler, include the following in your ``Gemfile``: - -.. code-block:: ruby - - gem 'mongoid' - -Using Mongoid with a New Rails Application -========================================== - -By using the `railsmdb CLI `_ a new -Ruby on Rails application can be quickly generated using the same options as -``rails new``, but configured to work with MongoDB: - -.. code-block:: sh - - railsmdb new my_new_rails_app - -The ``rails`` CLI can also be used, however when creating a new Rails application -and where Mongoid will be used for data access, provide the ``--skip-active-record`` -flag to the ``rails new`` command to avoid depending on and configuring ActiveRecord. - -Additional examples can be found in the `tutorials `_. - -Using Mongoid with an Existing Rails Application -================================================ - -Using the `railsmdb CLI `_ an existing -Rails application can easily be configured for use with Mongoid: - -.. code-block:: sh - - railsmdb setup - -Converting an existing Rails application without using ``railsmdb`` can be done -by updating the ``config/application.rb`` file to remove the ``require 'rails/all'`` -line and explicitly include the required frameworks (which could be all of the -frameworks provided by Rails with the exception ofActiveRecord). -Any references to ActiveRecord in files in the ``config`` directory and in the -models also need to be removed. diff --git a/docs/meta/404.txt b/docs/meta/404.txt deleted file mode 100644 index 4143ded8d6..0000000000 --- a/docs/meta/404.txt +++ /dev/null @@ -1,7 +0,0 @@ -:orphan: - -************** -File not found -************** - -The URL you requested does not exist or has been removed. diff --git a/docs/nesting-levels.txt b/docs/nesting-levels.txt deleted file mode 100644 index 2973410d08..0000000000 --- a/docs/nesting-levels.txt +++ /dev/null @@ -1,20 +0,0 @@ -This file is not part of Mongoid documentation proper, it is an internal -reference for the nesting levels that other files should be using. - -Mongoid documentation nesting levels: - -********** -Page Title -********** - -First Level Heading -=================== - -Second Level Heading --------------------- - -Third Level Heading -``````````````````` - -Fourth Level Heading -~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/reference/aggregation.txt b/docs/reference/aggregation.txt deleted file mode 100644 index 5a5c83d965..0000000000 --- a/docs/reference/aggregation.txt +++ /dev/null @@ -1,203 +0,0 @@ -.. _aggregation-pipeline: - -******************** -Aggregation Pipeline -******************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -Mongoid exposes `MongoDB's aggregation pipeline -`_, -which is used to construct flows of operations that process and return results. -The aggregation pipeline is a superset of the deprecated -:ref:`map/reduce framework ` functionality. - - -Basic Usage -=========== - -.. _aggregation-pipeline-example-multiple-collections: - -Querying Across Multiple Collections -```````````````````````````````````` - -The aggregation pipeline may be used for queries involving multiple -referenced associations at the same time: - -.. code-block:: ruby - - class Band - include Mongoid::Document - has_many :tours - has_many :awards - field :name, type: String - end - - class Tour - include Mongoid::Document - belongs_to :band - field :year, type: Integer - end - - class Award - include Mongoid::Document - belongs_to :band - field :name, type: String - end - -To retrieve bands that toured since 2000 and have at least one award, one -could do the following: - -.. code-block:: ruby - - band_ids = Band.collection.aggregate([ - { '$lookup' => { - from: 'tours', - localField: '_id', - foreignField: 'band_id', - as: 'tours', - } }, - { '$lookup' => { - from: 'awards', - localField: '_id', - foreignField: 'band_id', - as: 'awards', - } }, - { '$match' => { - 'tours.year' => {'$gte' => 2000}, - 'awards._id' => {'$exists' => true}, - } }, - {'$project' => {_id: 1}}, - ]) - bands = Band.find(band_ids.to_a) - -Note that the aggregation pipeline, since it is implemented by the Ruby driver -for MongoDB and not Mongoid, returns raw ``BSON::Document`` objects rather than -``Mongoid::Document`` model instances. The above example projects only -the ``_id`` field which is then used to load full models. An alternative is -to not perform such a projection and work with raw fields, which would eliminate -having to send the list of document ids to Mongoid in the second query -(which could be large). - - -.. _aggregation-pipeline-builder-dsl: - -Builder DSL -=========== - -Mongoid provides limited support for constructing the aggregation pipeline -itself using a high-level DSL. The following aggregation pipeline operators -are supported: - -- `$group `_ -- `$project `_ -- `$unwind `_ - -To construct a pipeline, call the corresponding aggregation pipeline methods -on a ``Criteria`` instance. Aggregation pipeline operations are added to the -``pipeline`` attribute of the ``Criteria`` instance. To execute the pipeline, -pass the ``pipeline`` attribute value to ``Collection#aggragegate`` method. - -For example, given the following models: - -.. code-block:: ruby - - class Tour - include Mongoid::Document - - embeds_many :participants - - field :name, type: String - field :states, type: Array - end - - class Participant - include Mongoid::Document - - embedded_in :tour - - field :name, type: String - end - -We can find out which states a participant visited: - -.. code-block:: ruby - - criteria = Tour.where('participants.name' => 'Serenity',). - unwind(:states). - group(_id: 'states', :states.add_to_set => '$states'). - project(_id: 0, states: 1) - - pp criteria.pipeline - # => [{"$match"=>{"participants.name"=>"Serenity"}}, - # {"$unwind"=>"$states"}, - # {"$group"=>{"_id"=>"states", "states"=>{"$addToSet"=>"$states"}}}, - # {"$project"=>{"_id"=>0, "states"=>1}}] - - Tour.collection.aggregate(criteria.pipeline).to_a - - -group -````` - -The ``group`` method adds a `$group aggregation pipeline stage -`_. - -The field expressions support Mongoid symbol-operator syntax: - -.. code-block:: ruby - - criteria = Tour.all.group(_id: 'states', :states.add_to_set => '$states') - criteria.pipeline - # => [{"$group"=>{"_id"=>"states", "states"=>{"$addToSet"=>"$states"}}}] - -Alternatively, standard MongoDB aggregation pipeline syntax may be used: - -.. code-block:: ruby - - criteria = Tour.all.group(_id: 'states', states: {'$addToSet' => '$states'}) - - -project -``````` - -The ``project`` method adds a `$project aggregation pipeline stage -`_. - -The argument should be a Hash specifying the projection: - -.. code-block:: ruby - - criteria = Tour.all.project(_id: 0, states: 1) - criteria.pipeline - # => [{"$project"=>{"_id"=>0, "states"=>1}}] - - -.. _unwind-dsl: - -unwind -`````` - -The ``unwind`` method adds an `$unwind aggregation pipeline stage -`_. - -The argument can be a field name, specifiable as a symbol or a string, or -a Hash or a ``BSON::Document`` instance: - -.. code-block:: ruby - - criteria = Tour.all.unwind(:states) - criteria = Tour.all.unwind('states') - criteria.pipeline - # => [{"$unwind"=>"$states"}] - - criteria = Tour.all.unwind(path: '$states') - criteria.pipeline - # => [{"$unwind"=>{:path=>"$states"}}] diff --git a/docs/reference/associations.txt b/docs/reference/associations.txt deleted file mode 100644 index e8f9c7b33e..0000000000 --- a/docs/reference/associations.txt +++ /dev/null @@ -1,1655 +0,0 @@ -.. _associations: - -************ -Associations -************ - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Referenced Associations -======================= - -Mongoid supports the ``has_one``, ``has_many``, ``belongs_to`` and -``has_and_belongs_to_many`` associations familiar to ActiveRecord users. - - -Has One -------- - -Use the ``has_one`` macro to declare that the parent has a child stored in -a separate collection. The child is optional by default: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_one :studio - end - -When using ``has_one``, the child model must use ``belongs_to`` to declare the -association with the parent: - -.. code-block:: ruby - - class Studio - include Mongoid::Document - - belongs_to :band - end - -Given the above definitions, every child document contains a reference to -its respective parent document: - -.. code-block:: ruby - - band = Band.create!(studio: Studio.new) - # => # - - band.studio - # => # - -Use validations to require that the child is present: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_one :studio - - validates_presence_of :studio - end - - -Has Many --------- - -Use the ``has_many`` association to declare that the parent has zero or more -children stored in a separate collection: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_many :members - end - -Like with ``has_one``, the child model must use ``belongs_to`` to declare the -association with the parent: - -.. code-block:: ruby - - class Member - include Mongoid::Document - - belongs_to :band - end - -Also as with ``has_one``, the child documents contain references to their -respective parents: - -.. code-block:: ruby - - band = Band.create!(members: [Member.new]) - # => # - - band.members - # => [#] - -Use validations to require that at least one child is present: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_many :members - - validates_presence_of :members - end - - -Queries -``````` - -.. _has-many-any: - -``any?`` -~~~~~~~~ - -Use the ``any?`` method on the association to efficiently determine whether -the association contains any documents, without retrieving the entire set -of documents from the database: - -.. code-block:: ruby - - band = Band.first - band.members.any? - -``any?`` also implements the `Enumerable#any? API -`_, allowing -filtering with a block: - -.. code-block:: ruby - - band = Band.first - band.members.any? { |member| member.instrument == 'piano' } - -... or by a class name which can be useful for polymorphic associations: - -.. code-block:: ruby - - class Drummer < Member - end - - band = Band.first - band.members.any?(Drummer) - -If the association is already loaded, ``any?`` inspects the loaded -documents and does not query the database: - -.. code-block:: ruby - - band = Band.first - # Queries the database - band.members.any? - - band.members.to_a - - # Does not query the database - band.members.any? - -Note that simply calling ``any?`` would *not* load the association -(since ``any?`` only retrieves the _id field of the first matching document). - -``exists?`` -~~~~~~~~~~~ - -The ``exists?`` method on the association determines whether there are -any *persisted* documents in the association. Unlike the ``any?`` method: - -- ``exists?`` always queries the database, even if the association is already - loaded. -- ``exists?`` does not consider non-persisted documents. -- ``exists?`` does not allow filtering in the application like ``any?`` does, - and does not take any arguments. - -The following example illustrates the difference between ``exists?`` and -``any?``: - -.. code-block:: ruby - - band = Band.create! - # Member is not persisted. - band.members.build - - band.members.any? - # => true - band.members.exists? - # => false - - # Persist the member. - band.members.map(&:save!) - - band.members.any? - # => true - band.members.exists? - # => true - - -Belongs To ----------- - -Use the ``belongs_to`` macro to associate a child with a parent stored in a -separate collection. The ``_id`` of the parent (if a parent is associated) -is stored in the child. - -By default, if a ``belongs_to`` association is defined on a model, it must be -provided a value for a model instance to be saved. Use the ``optional: true``` -option to make the instances persistable without specifying the parent: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_one :studio - end - - class Studio - include Mongoid::Document - - belongs_to :band, optional: true - end - - studio = Studio.create! - # => # - -To change the default behavior of ``belongs_to`` associations to not require -their respective parents globally, set the ``belongs_to_required_by_default`` -:ref:`configuration option ` to ``false``. - -Although ``has_one`` and ``has_many`` associations require the -corresponding ``belongs_to`` association to be defined on the child, -``belongs_to`` may also be used without a corresponding ``has_one`` or -``has_many`` macro. In this case the child is not accessible from the parent -but the parent is accessible from the child: - -.. code-block:: ruby - - class Band - include Mongoid::Document - end - - class Studio - include Mongoid::Document - - belongs_to :band - end - -For clarity it is possible to add the ``inverse_of: nil`` option in cases when -the parent does not define the association: - -.. code-block:: ruby - - class Band - include Mongoid::Document - end - - class Studio - include Mongoid::Document - - belongs_to :band, inverse_of: nil - end - - -Has And Belongs To Many ------------------------ - -Use the ``has_and_belongs_to_many`` macro to declare a many-to-many -association: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_and_belongs_to_many :tags - end - - class Tag - include Mongoid::Document - - has_and_belongs_to_many :bands - end - -Both model instances store a list of ids of the associated models, if any: - -.. code-block:: ruby - - band = Band.create!(tags: [Tag.create!]) - # => # - - band.tags - # => [#] - -You can create a one-sided ``has_and_belongs_to_many`` association to store -the ids only in one document using the ``inverse_of: nil`` option: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_and_belongs_to_many :tags, inverse_of: nil - end - - class Tag - include Mongoid::Document - end - - band = Band.create!(tags: [Tag.create!]) - # => # - - band.tags - # => [#] - -A one-sided ``has_and_belongs_to_many`` association is, naturally, only -usable from the model where it is defined. - -.. note:: - - Given two models, A and B where A ``has_and_belongs_to_many`` B, - when adding a document of type B to the HABTM association on a document of - type A, Mongoid will not update the ``updated_at`` field for the document of - type A, but will update the ``updated_at`` field for the document of type B. - -Querying Referenced Associations --------------------------------- - -In most cases, efficient queries across referenced associations (and in general -involving data or conditions or multiple collections) are performed using -the aggregation pipeline. Mongoid helpers for constructing aggregation pipeline -queries are described in the :ref:`aggregation pipeline ` -section. - -For simple queries, the use of aggregation pipeline may be avoided and -associations may be queried directly. When querying associations directly, -all conditions must be on that association's collection only (which typically -means association in question and any associations embedded in it). - -For example, given the following models: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_many :tours - has_many :awards - - field :name, type: String - end - - class Tour - include Mongoid::Document - - belongs_to :band - - field :year, type: Integer - end - - class Award - include Mongoid::Document - - belongs_to :band - - field :name, type: String - end - -One could retrieve all bands that have toured since 2000 as follows: - -.. code-block:: ruby - - band_ids = Tour.where(year: {'$gte' => 2000}).pluck(:band_id) - bands = Band.find(band_ids) - -The conditions on ``Tour`` can be arbitrarily complex, but they must all -be on the same ``Tour`` document (or documents embedded in ``Tour``). - -To find awards for bands that have toured since 2000: - -.. code-block:: ruby - - band_ids = Tour.where(year: {'$gte' => 2000}).pluck(:band_id) - awards = Award.where(band_id: {'$in' => band_ids}) - - -Embedded Associations -===================== - -Thanks to MongoDB's document model, Mongoid also offers embedded associations -which allow documents of different types to be stored hierarchically -in the same collection. Embedded associations are defined using -``embeds_one``, ``embeds_many`` and ``embedded_in`` macros, plus -``recursively_embeds_one`` and ``recursively_embeds_many`` for recursive -embedding. - -Embeds One ----------- - -One to one associations where the children are embedded in the parent -document are defined using Mongoid's ``embeds_one`` and ``embedded_in`` macros. - -Defining -```````` - -The parent document of the association should use the ``embeds_one`` macro to -indicate is has one embedded child, where the document that is embedded uses -``embedded_in``. Definitions are required on both sides to the association -in order for it to work properly. - -.. code-block:: ruby - - class Band - include Mongoid::Document - embeds_one :label - end - - class Label - include Mongoid::Document - field :name, type: String - embedded_in :band - end - -Storage -``````` - -Documents that are embedded using the ``embeds_one`` macro are stored as a -hash inside the parent in the parent's database collection. - -.. code-block:: ruby - - { - "_id" : ObjectId("4d3ed089fb60ab534684b7e9"), - "label" : { - "_id" : ObjectId("4d3ed089fb60ab534684b7e0"), - "name" : "Mute", - } - } - -You can optionally tell Mongoid to store the embedded document in a different -attribute other than the name, by providing the ``:store_as`` option. - -.. code-block:: ruby - - class Band - include Mongoid::Document - embeds_one :label, store_as: "lab" - end - - -Embeds Many ------------ - -One to many relationships where the children are embedded in the parent -document are defined using Mongoid's ``embeds_many`` and ``embedded_in`` macros. - -Defining -```````` - -The parent document of the association should use the ``embeds_many`` macro -to indicate it has many embedded children, where the document that is -embedded uses ``embedded_in``. Definitions are required on both sides of -the association in order for it to work properly. - -.. code-block:: ruby - - class Band - include Mongoid::Document - embeds_many :albums - end - - class Album - include Mongoid::Document - field :name, type: String - embedded_in :band - end - -Storage -``````` - -Documents that are embedded using the ``embeds_many`` macro are stored as -an array of hashes inside the parent in the parent's database collection. - -.. code-block:: ruby - - { - "_id" : ObjectId("4d3ed089fb60ab534684b7e9"), - "albums" : [ - { - "_id" : ObjectId("4d3ed089fb60ab534684b7e0"), - "name" : "Violator", - } - ] - } - -You can optionally tell Mongoid to store the embedded document in a different -attribute other than the name, by providing the ``:store_as`` option. - -.. code-block:: ruby - - class Band - include Mongoid::Document - embeds_many :albums, store_as: "albs" - end - -Recursive Embedding -------------------- - -A document can recursively embed itself using ``recursively_embeds_one`` or -``recursively_embeds_many``, which provides accessors for the parent and -children via ``parent_`` and ``child_`` methods. - -.. code-block:: ruby - - class Tag - include Mongoid::Document - field :name, type: String - recursively_embeds_many - end - - root = Tag.new(name: "programming") - child_one = root.child_tags.build - child_two = root.child_tags.build - - root.child_tags # [ child_one, child_two ] - child_one.parent_tag # [ root ] - child_two.parent_tag # [ root ] - - class Node - include Mongoid::Document - recursively_embeds_one - end - - root = Node.new - child = Node.new - root.child_node = child - - root.child_node # child - child.parent_node # root - -Referencing Vs Embedding ------------------------- - -While a complete discussion of referencing vs embedding is beyond the scope -of this tutorial, here are some high level considerations for choosing -one over the other. - -When an association is embedded, both parent and child documents are stored -in the same collection. This permits efficient persistence and retrieval -when both are used/needed. For example, if the navigation bar on a web site -shows attributes of a user that are stored in documents themselves, it is -often a good idea to use embedded associations. - -Using embedded associations allows using MongoDB tools like the -`aggregation pipeline -`_ to query -these documents in a powerful way. - -Because embedded documents are stored as part of their parent top-level -documents, it is not possible to persist an embedded document by itself, -nor is it possible to retrieve embedded documents directly. However, -embedded documents can still be efficiently queried and retrieved with the -help of MongoDB projection operation: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :started_on, type: Date - embeds_one :label - end - - class Label - include Mongoid::Document - field :name, type: String - embedded_in :band - end - - # Retrieve labels for bands started in the last year. - # - # Sends a find query like this: - # {"find"=>"bands", - # "filter"=>{"started_on"=>{"$gt"=>2018-07-01 00:00:00 UTC}}, - # "projection"=>{"_id"=>1, "label"=>1}} - Band.where(started_on: {'$gt' => Time.now - 1.year}).only(:label).map(&:label).compact.uniq - -Setting Stale Values on Referenced Associations -``````````````````````````````````````````````` - -Setting a stale value to a referenced association can sometimes result in -a ``nil`` value being persisted to the database. Take the following case: - -.. code-block:: ruby - - class Post - include Mongoid::Document - - has_one :comment, inverse_of: :post - end - - class Comment - include Mongoid::Document - - belongs_to :post, inverse_of: :comment, optional: true - end - - post.comment = comment1 - post.reload - -At this point, ``post.comment`` is set to ``comment1``, however since a reload -happened, ``post.comment`` does not refer to the same object as ``comment1``. -Meaning, updating one object does not implicitly update the other. This matters -for the next operation: - -.. code-block:: ruby - - post.comment = comment2 - post.reload - -Now, ``post.comment`` is set to ``comment2``, and the ``post_id`` of the old -comment is set to ``nil``. However, the value that was assigned to -``post.comment`` did not refer to the same object as ``comment1``, therefore, -while the old value of ``post.comment`` was updated to have a ``nil`` -``post_id``, ``comment1`` still has the ``post_id`` set. - -.. code-block:: ruby - - post.comment = comment1 - post.reload - -Finally, this last assignment attempts to set the ``post_id`` on ``comment1``, -which should be ``nil`` at this point, but is set to the old ``post_id``. -During this operation, the ``post_id`` is cleared from ``comment2``, and the -new ``post_id`` is set on ``comment1``. However, since the ``post_id`` was -already set on ``comment1``, nothing is persisted, and we end up with both -comments having a ``nil`` ``post_id``. At this point, running ``post.comment`` -returns ``nil``. - - -Querying Embedded Associations ------------------------------- - -When querying top-level documents, conditions can be specified on documents -in embedded associations using the dot notation. For example, given the -following models: - -.. code-block:: ruby - - class Band - include Mongoid::Document - embeds_many :tours - embeds_many :awards - field :name, type: String - end - - class Tour - include Mongoid::Document - embedded_in :band - field :year, type: Integer - end - - class Award - include Mongoid::Document - embedded_in :band - field :name, type: String - end - -To retrieve bands based on tour attributes, use the dot notation as follows: - -.. code-block:: ruby - - # Get all bands that have toured since 2000 - Band.where('tours.year' => {'$gte' => 2000}) - -To retrieve only documents of embedded associations, without retrieving -top-level documents, use the ``pluck`` projection method: - -.. code-block:: ruby - - # Get awards for bands that have toured since 2000 - Band.where('tours.year' => {'$gte' => 2000}).pluck(:awards) - -.. _embedded-matching: - -Querying Loaded Associations -```````````````````````````` - -Mongoid query methods can be used on embedded associations of documents which -are already loaded in the application. This mechanism is called -"embedded matching" and it is implemented entirely in Mongoid--the queries -are NOT sent to the server. - -The following operators are supported: - -- :manual:`Comparison operators ` -- :manual:`Logical operators ` -- :manual:`Array query operators ` -- :manual:`$exists ` -- :manual:`$mod ` -- :manual:`$type ` -- :manual:`$regex ` (``$options`` field - is only supported when the ``$regex`` argument is a string) -- :manual:`Bitwise operators ` -- :manual:`$comment ` - -For example, using the model definitions just given, we could query -tours on a loaded band: - -.. code-block:: ruby - - band = Band.where(name: 'Astral Projection').first - tours = band.tours.where(year: {'$gte' => 2000}) - -Embedded Matching vs Server Behavior -```````````````````````````````````` - -Mongoid's embedded matching aims to support the same functionality and -semantics as native queries on the latest MongoDB server version. -Note the following known limitations: - -- Embedded matching is not implemented for :ref:`text search `, - :manual:`geospatial query operators `, - operators that execute JavaScript code (:manual:`$where `) - and operators that are implemented via other server functionality such as - :manual:`$expr ` - and :manual:`$jsonSchema `. - -- Mongoid DSL expands ``Range`` arguments to hashes with ``$gte`` and ``$lte`` - conditions. `In some cases `_ - this creates bogus queries. Embedded matchers raise the ``InvalidQuery`` - exception in these cases. The operators that are known to be affected are - ``$elemMatch``, ``$eq``, ``$gt``, ``$gte``, ``$lt``, ``$lte`` and ``$ne``. - -- When performing embedded matching with ``$regex``, `it is not currently - possible `_ to specify a - regular expression object as the pattern and also provide options. - -- MongoDB Server 4.0 and earlier servers do not validate ``$type`` arguments strictly - (for example, allowing invalid arguments like 0). This is validated more strictly on - the client side. - - -.. _omit-id: - -Omitting ``_id`` Fields ------------------------ - -By default, Mongoid adds an ``_id`` field to each embedded document. This -permits easy referencing of and operations on the embedded documents. - -These ``_id`` fields may be omitted to save storage space. To do so, -:ref:`override the _id field definition in the child documents ` -and remove the default value: - -.. code-block:: ruby - - class Order - include Mongoid::Document - - embeds_many :line_items - end - - class LineItem - include Mongoid::Document - - embedded_in :order - - field :_id, type: Object - end - -In the current version of Mongoid the field definition is required, but -without a default value specified no value will be stored in the database. -A future version of Mongoid may allow removing previously defined fields. - -.. note:: - - Removing the ``_id`` field means that embedded documents must be identified - by their content attribute values during queries, updates and deletes. - - -Deleting --------- - -Mongoid provides three methods for deleting children from ``embeds_many`` -associations: ``clear``, ``destroy_all`` and ``delete_all``. - -``clear`` -````````` - -The ``clear`` method uses the :manual:`$unset operator -` to remove the entire association from the -host document. It does not run destroy callbacks on the documents being removed, -acting like ``delete_all`` in this regard: - -.. code-block:: ruby - - band = Band.find(...) - band.tours.clear - -If ``clear`` is called on an association in an unsaved host document, it will -still try to remove the association from the database based on the host -document's ``_id``: - -.. code-block:: ruby - - band = Band.find(...) - band.tours << Tour.new(...) - - unsaved_band = Band.new(id: band.id, tours: [Tour.new]) - # Removes all tours from the persisted band due to _id match. - unsaved_band.tours.clear - - band.tours - # => [] - -``delete_all`` -`````````````` - -The ``delete_all`` method removes the documents that are in the association -using the :manual:`$pullAll operator `. -Unlike ``clear``, ``delete_all``: - -- Loads the association, if it wasn't yet loaded; -- Only removes the documents that exist in the application. - -``delete_all`` does not run destroy callbacks on the documents being removed. - -Example: - -.. code-block:: ruby - - band = Band.find(...) - band.tours.delete_all - - -``destroy_all`` -``````````````` - -The ``delete_all`` method removes the documents that are in the association -using the :manual:`$pullAll operator ` -while running the destroy callbacks. Like ``delete_all``, ``destroy_all`` -loads the entire association if it wasn't yet loaded and it only removes -documents that exist in the application: - -.. code-block:: ruby - - band = Band.find(...) - band.tours.destroy_all - - -.. _hash-assignment: - -Hash Assignment ---------------- - -Embedded associations allow the user to assign a ``Hash`` instead of a document -to an association. On assignment, this hash is coerced into a document of the -class of the association that it's being assigned to. Take the following -example: - -.. code:: ruby - - class Band - include Mongoid::Document - embeds_many :albums - end - - class Album - include Mongoid::Document - field :name, type: String - embedded_in :band - end - - band = Band.create! - band.albums = [ { name: "Narrow Stairs" }, { name: "Transatlanticism" } ] - p band.albums - # => [ #, # ] - -This works for ``embeds_one``, ``embeds_many``, and ``embedded_in`` associations. -Note that you cannot assign hashes to referenced associations. - - -Common Behavior -=============== - -Extensions ----------- - -All associations can have extensions, which provides a way to add application specific -functionality to the association. They are defined by providing a block to the association definition. - -.. code-block:: ruby - - class Person - include Mongoid::Document - embeds_many :addresses do - def find_by_country(country) - where(country: country).first - end - def chinese - _target.select { |address| address.country == "China" } - end - end - end - - person.addresses.find_by_country("Mongolia") # returns address - person.addresses.chinese # returns [ address ] - -Custom Association Names ------------------------- - -You can name your associations whatever you like, but if the class cannot be inferred by -Mongoid from the name, and neither can the opposite side you'll want to provide the -macro with some additional options to tell Mongoid how to hook them up. - -.. code-block:: ruby - - class Car - include Mongoid::Document - embeds_one :engine, class_name: "Motor", inverse_of: :machine - end - - class Motor - include Mongoid::Document - embedded_in :machine, class_name: "Car", inverse_of: :engine - end - -Custom Primary & Foreign Keys ------------------------------ - -The fields used when looking up associations can be explicitly specified. -The default is to use ``id`` on the "parent" association and ``#{association_name}_id`` -on the "child" association, for example with a has_many/belongs_to: - -.. code-block:: ruby - - class Company - include Mongoid::Document - has_many :emails - end - - class Email - include Mongoid::Document - belongs_to :company - end - - company = Company.find(id) - # looks up emails where emails.company_id == company.id - company.emails - -Specify a different ``primary_key`` to change the field name on the "parent" -association and ``foreign_key`` to change the field name on the "child" -association: - -.. code-block:: ruby - - class Company - include Mongoid::Document - field :c, type: String - has_many :emails, foreign_key: 'c_ref', primary_key: 'c' - end - - class Email - include Mongoid::Document - # This definition of c_ref is automatically generated by Mongoid: - # field :c_ref, type: Object - # But the type can also be specified: - field :c_ref, type: String - belongs_to :company, foreign_key: 'c_ref', primary_key: 'c' - end - - company = Company.find(id) - # looks up emails where emails.c_ref == company.c - company.emails - -With a has_and_belongs_to_many association, since the data is stored on both -sides of the association, there are 4 fields configurable when the association -is defined: - -- ``:primary_key`` is the field on the remote model that contains the value - by which the remote model is looked up. -- ``:foreign_key`` is the field on the local model which stores the - ``:primary_key`` values. -- ``:inverse_primary_key`` is the field on the local model that the remote - model uses to look up the local model documents. -- ``:inverse_foreign_key`` is the field on the remote model storing the - values in ``:inverse_primary_key``. - -An example might make this more clear: - -.. code-block:: ruby - - class Company - include Mongoid::Document - - field :c_id, type: Integer - field :e_ids, type: Array - - has_and_belongs_to_many :employees, - primary_key: :e_id, foreign_key: :e_ids, - inverse_primary_key: :c_id, inverse_foreign_key: :c_ids - end - - class Employee - include Mongoid::Document - - field :e_id, type: Integer - field :c_ids, type: Array - - has_and_belongs_to_many :companies, - primary_key: :c_id, foreign_key: :c_ids, - inverse_primary_key: :e_id, inverse_foreign_key: :e_ids - end - - company = Company.create!(c_id: 123) - # => # - - employee = Employee.create!(e_id: 456) - # => # - - company.employees << employee - - company - # => # - - employee - # => # - -Note that just like with the default ``#{association_name}_id`` field, -Mongoid automatically adds a field for the custom foreign key ``c_ref`` to -the model. However, since Mongoid doesn't know what type of data should be -allowed in the field, the field is created with a type of Object. It is a -good idea to explicitly define the field with the appropriate type. - - -.. _association-scope: - -Custom Scopes -------------- - -You may set a specific scope on an association using the ``:scope`` parameter. -The scope is an additional filter that restricts which objects are considered -to be a part of the association - a scoped association will return only -documents which satisfy the scope condition.. The scope may be either: - -- a ``Proc`` with arity zero, or -- a ``Symbol`` which references a :ref:`named scope ` on the - associated model. - -.. code-block:: ruby - - class Trainer - has_many :pets, scope: -> { where(species: 'dog') } - has_many :toys, scope: :rubber - end - - class Pet - belongs_to :trainer - end - - class Toy - scope :rubber, where(material: 'rubber') - belongs_to :trainer - end - -.. note:: - - It is possible to add documents that do not satisfy an association's scope - to that association. In this case, such documents will appear associated - in memory, and will be saved to the database, but will not be present when - the association is queried in the future. For example: - - .. code-block:: ruby - - trainer = Trainer.create! - dog = Pet.create!(trainer: trainer, species: 'dog') - cat = Pet.create!(trainer: trainer, species: 'cat') - - trainer.pets #=> [dog, cat] - - trainer.reload.pets #=> [dog] - -.. note:: - - Mongoid's syntax for scoped association differs from that of ActiveRecord. - Mongoid uses the ``:scope`` keyword argument for consistency with other - association options, whereas in ActiveRecord the scope is a positional - argument. - - -Validations ------------ - -It is important to note that by default, Mongoid will validate the children of any -association that are loaded into memory via a ``validates_associated``. The associations that -this applies to are: - -- ``embeds_many`` -- ``embeds_one`` -- ``has_many`` -- ``has_one`` -- ``has_and_belongs_to_many`` - -If you do not want this behavior, you may turn it off when defining the association. - -.. code-block:: ruby - - class Person - include Mongoid::Document - - embeds_many :addresses, validate: false - has_many :posts, validate: false - end - - -Polymorphism ------------- - -One to one and one to many associations support polymorphism, which is -having a single association potentially contain objects of different classes. -For example, we could model an organization in which departments and teams -have managers as follows: - -.. code-block:: ruby - - class Department - include Mongoid::Document - - has_one :manager, as: :unit - end - - class Team - include Mongoid::Document - - has_one :manager, as: :unit - end - - class Manager - include Mongoid::Document - - belongs_to :unit, polymorphic: true - end - - dept = Department.create! - team = Team.create! - - alice = Manager.create!(unit: dept) - alice.unit == dept - # => true - dept.manager == alice - # => true - -To provide another example, suppose we want to track price history for -products and bundles. This can be achieved via an embedded one to many -polymorphic association: - -.. code-block:: ruby - - class Product - include Mongoid::Document - - field :name, type: String - has_and_belongs_to_many :bundles - - embeds_many :prices, as: :item - end - - class Bundle - include Mongoid::Document - - field :name, type: String - has_and_belongs_to_many :products - - embeds_many :prices, as: :item - end - - class Price - include Mongoid::Document - - embedded_in :item, polymorphic: true - end - - pants = Product.create!(name: 'Pants', - prices: [Price.new, Price.new]) - costume = Bundle.create!(name: 'Costume', products: [pants], - prices: [Price.new, Price.new]) - -To define a polymorphic association, specify the ``polymorphic: true`` option -on the child association and add the ``as: :association_name`` option to the -parent association. - -Note that Mongoid currently supports polymorphism only in one direction - from -the child to the parent. For example, polymorphism cannot be used to specify -that a bundle may contain other bundles or products: - -.. code-block:: ruby - - class Bundle - include Mongoid::Document - - # Does not work: - has_many :items, polymorphic: true - end - -``has_and_belongs_to_many`` associations do not support polymorphism. - - -Cascading Callbacks -------------------- - -If you want the embedded document callbacks to fire when calling a persistence -operation on its parent, you will need to provide the cascade callbacks option -to the association. - -.. code-block:: ruby - - class Band - include Mongoid::Document - embeds_many :albums, cascade_callbacks: true - embeds_one :label, cascade_callbacks: true - end - - band.save # Fires all save callbacks on the band, albums, and label. - - -.. _dependent-behavior: - -Dependent Behavior ------------------- - -You can provide dependent options to referenced associations to instruct Mongoid -how to handle situations where one side of the association is deleted, or is attempted -to be deleted. The options are as follows: - -- ``:delete_all``: Delete the child document(s) without running any of the model callbacks. -- ``:destroy``: Destroy the child document(s) and run all of the model callbacks. -- ``:nullify``: Set the foreign key field of the child document to nil. The child may become orphaned if it is ordinarily only referenced via the parent. -- ``:restrict_with_exception``: ``raise`` an error if the child is not empty. -- ``:restrict_with_error``: Cancel operation and return false if the child is not empty. - -If no ``:dependent`` option is provided, deleting the parent document leaves the child document unmodified -(in other words, the child document continues to reference the now deleted parent document via the foreign key field). -The child may become orphaned if it is ordinarily only referenced via the parent. - -.. code-block:: ruby - - class Band - include Mongoid::Document - has_many :albums, dependent: :delete_all - belongs_to :label, dependent: :nullify - end - - class Album - include Mongoid::Document - belongs_to :band - end - - class Label - include Mongoid::Document - has_many :bands, dependent: :restrict_with_exception - end - - label = Label.first - label.bands.push(Band.first) - label.delete # Raises an error since bands is not empty. - - Band.first.destroy # Will delete all associated albums. - - -Autosaving ----------- - -One core difference between Mongoid and ActiveRecord is that Mongoid does not -automatically save associated documents for referenced (i.e., non-embedded) -associations when the parent is saved, for performance reasons. - -If autosaving is not used, it is possible to create dangling references -to non-existent documents via associations: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_many :albums - end - - class Album - include Mongoid::Document - - belongs_to :band - end - - band = Band.new - album = Album.create!(band: band) - - # The band is not persisted at this point. - - album.reload - - album.band_id - # => BSON::ObjectId('6257699753aefe153121a3d5') - - # Band does not exist. - album.band - # => nil - -To make referenced associations save automatically when the parent is saved, -add the ``:autosave`` option to the association: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_many :albums - end - - class Album - include Mongoid::Document - - belongs_to :band, autosave: true - end - - band = Band.new - album = Album.create!(band: band) - - # The band is persisted at this point. - - album.reload - - album.band_id - # => BSON::ObjectId('62576b4b53aefe178b65b8e3') - - album.band - # => # - -The autosaving functionality is automatically added to an association when -using ``accepts_nested_attributes_for``, so that the application does not -need to track which associations were modified when processing a form -submission. - -Embedded associations always autosave, because they are stored as part of the -parent document. - -Some operations on associations always save the parent and the child documents -as part of the operation, regardless of whether autosaving is enabled. -A non-exhaustive list of these operations is as follows: - -- Assignment to the association: - - .. code-block:: ruby - - # Saves the band and the album. - band.albums = [Album.new] - -- ``push``, ``<<``: - - .. code-block:: ruby - - band.albums << Album.new - band.albums.push(Album.new) - - -Existence Predicates --------------------- - -All associations have existence predicates on them in the form of ``name?`` and ``has_name?`` -to check if the association is blank. - -.. code-block:: ruby - - class Band - include Mongoid::Document - embeds_one :label - embeds_many :albums - end - - band.label? - band.has_label? - band.albums? - band.has_albums? - -Autobuilding ------------- - -One to one associations (``embeds_one``, ``has_one``) have an autobuild option which tells -Mongoid to instantiate a new document when the association is accessed and it is ``nil``. - -.. code-block:: ruby - - class Band - include Mongoid::Document - embeds_one :label, autobuild: true - has_one :producer, autobuild: true - end - - band = Band.new - band.label # Returns a new empty label. - band.producer # Returns a new empty producer. - -Touching --------- -Any ``belongs_to`` association can take an optional ``:touch`` option which -will cause the parent document to be touched whenever the child document is -updated: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name - belongs_to :label, touch: true - end - - band = Band.first - band.name = "The Rolling Stones" - band.save! # Calls touch on the parent label. - band.touch # Calls touch on the parent label. - -``:touch`` can also take a string or symbol argument specifying a field to -be touched on the parent association in addition to updated_at: - -.. code-block:: ruby - - class Label - include Mongoid::Document - include Mongoid::Timestamps - field :bands_updated_at, type: Time - has_many :bands - end - - class Band - include Mongoid::Document - belongs_to :label, touch: :bands_updated_at - end - - label = Label.create! - band = Band.create!(label: label) - - band.touch # Updates updated_at and bands_updated_at on the label. - -When an embedded document is touched, its parents are recursively touched -through the composition root (because all of the parents are necessarily saved -when the embedded document is saved). The ``:touch`` attribute therefore is -unnecessary on ``embedded_in`` associations. - -Mongoid currently `does not support specifying an additional field to be -touched on an embedded_in association `_. - -``:touch`` should not be set to ``false`` on an ``embedded_in`` association, -since composition hierarchy is always updated upon a touch of an embedded -document. This is currently not enforced but enforcement is `intended in the -future `_. - -The counter_cache Option ------------------------- - -As with ActiveRecord, the ``:counter_cache`` option can be used on an association -to make finding the number of belonging objects more efficient. Also similar -to ActiveRecord, you must take into account that there will be an extra -attribute on the associated model. This means that with Mongoid, -you need to include ``Mongoid::Attributes::Dynamic`` on the associated model. -For example: - -.. code-block:: ruby - - class Order - include Mongoid::Document - belongs_to :customer, counter_cache: true - end - - class Customer - include Mongoid::Document - include Mongoid::Attributes::Dynamic - has_many :orders - end - -Association Proxies -------------------- - -Associations employ transparent proxies to the target objects. This can -cause surprising behavior in some situations. - -The method visibility may be lost when methods on association targets are -accessed, depending on the association: - -.. code-block:: ruby - - class Order - include Mongoid::Document - belongs_to :customer - - private - - def internal_status - 'new' - end - end - - class Customer - include Mongoid::Document - has_many :orders - - private - - def internal_id - 42 - end - end - - order = Order.new - customer = Customer.create!(orders: [order]) - - # has_many does not permit calling private methods on the target - customer.orders.first.internal_status - # NoMethodError (private method `internal_status' called for #) - - # belongs_to permits calling private methods on the target - order.customer.internal_id - # => 42 - -Association Metadata -==================== - -All associations in Mongoid contain metadata that holds information about the association in -question, and is a valuable tool for third party developers to use to extend Mongoid. - -You can access the association metadata of the association in a few different ways. - -.. code-block:: ruby - - # Get the metadata for a named association from the class or document. - Model.reflect_on_association(:association_name) - model.reflect_on_association(:association_name) - - # Get the metadata with a specific association itself on a specific - # document. - model.associations[:association_name] - -Attributes ----------- - -All associations contain a ``_target``, which is the proxied document or documents, a ``_base`` -which is the document the association hangs off, and ``_association`` which provides information -about the association. - -.. code-block:: ruby - - class Person - include Mongoid::Document - embeds_many :addresses - end - - person.addresses = [ address ] - person.addresses._target # returns [ address ] - person.addresses._base # returns person - person.addresses._association # returns the association metadata - -The Association Object ----------------------- - -The association object itself contains more information than one might know what to do -with, and is useful for developers of extensions to Mongoid. - - -.. list-table:: - :header-rows: 1 - :widths: 30 60 - - * - Method - - Description - * - ``Association#as`` - - Returns the name of the parent to a polymorphic child. - * - ``Association#as?`` - - Returns whether or not an as option exists. - * - ``Association#autobuilding?`` - - Returns whether or not the association is autobuilding. - * - ``Association#autosaving?`` - - Returns whether or not the association is autosaving. - * - ``Association#cascading_callbacks?`` - - Returns whether the association has callbacks cascaded down from the parent. - * - ``Association#class_name`` - - Returns the class name of the proxied document. - * - ``Association#cyclic?`` - - Returns whether the association is a cyclic association. - * - ``Association#dependent`` - - Returns the association's dependent option. - * - ``Association#destructive?`` - - Returns true if the association has a dependent delete or destroy. - * - ``Association#embedded?`` - - Returns whether the association is embedded in another document. - * - ``Association#forced_nil_inverse?`` - - Returns whether the association has a nil inverse defined. - * - ``Association#foreign_key`` - - Returns the name of the foreign key field. - * - ``Association#foreign_key_check`` - - Returns the name of the foreign key field dirty check method. - * - ``Association#foreign_key_setter`` - - Returns the name of the foreign key field setter. - * - ``Association#indexed?`` - - Returns whether the foreign key is auto indexed. - * - ``Association#inverses`` - - Returns the names of all inverse association. - * - ``Association#inverse`` - - Returns the name of a single inverse association. - * - ``Association#inverse_class_name`` - - Returns the class name of the association on the inverse side. - * - ``Association#inverse_foreign_key`` - - Returns the name of the foreign key field on the inverse side. - * - ``Association#inverse_klass`` - - Returns the class of the association on the inverse side. - * - ``Association#inverse_association`` - - Returns the metadata of the association on the inverse side. - * - ``Association#inverse_of`` - - Returns the explicitly defined name of the inverse association. - * - ``Association#inverse_setter`` - - Returns the name of the method used to set the inverse. - * - ``Association#inverse_type`` - - Returns the name for the polymorphic type field of the inverse. - * - ``Association#inverse_type_setter`` - - Returns the name for the polymorphic type field setter of the inverse. - * - ``Association#key`` - - Returns the name of the field in the attributes hash to use to get the association. - * - ``Association#klass`` - - Returns the class of the proxied documents in the association. - * - ``Association#name`` - - Returns the association name. - * - ``Association#options`` - - Returns self, for API compatibility with ActiveRecord. - * - ``Association#order`` - - Returns the custom sorting options on the association. - * - ``Association#polymorphic?`` - - Returns whether the association is polymorphic. - * - ``Association#setter`` - - Returns the name of the field to set the association. - * - ``Association#store_as`` - - Returns the name of the attribute to store an embedded association in. - * - ``Association#touchable?`` - - Returns whether or not the association has a touch option. - * - ``Association#type`` - - Returns the name of the field to get the polymorphic type. - * - ``Association#type_setter`` - - Returns the name of the field to set the polymorphic type. - * - ``Association#validate?`` - - Returns whether the association has an associated validation. diff --git a/docs/reference/callbacks.txt b/docs/reference/callbacks.txt deleted file mode 100644 index 972451dd0b..0000000000 --- a/docs/reference/callbacks.txt +++ /dev/null @@ -1,120 +0,0 @@ -.. _callbacks: - -********* -Callbacks -********* - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Mongoid implements many of the `ActiveRecord callbacks -`_. - - -Document Callbacks -================== - -Mongoid supports the following callbacks for :doc:`documents `: - -- ``after_initialize`` -- ``after_build`` -- ``before_validation`` -- ``after_validation`` -- ``before_create`` -- ``around_create`` -- ``after_create`` -- ``after_find`` -- ``before_update`` -- ``around_update`` -- ``after_update`` -- ``before_upsert`` -- ``around_upsert`` -- ``after_upsert`` -- ``before_save`` -- ``around_save`` -- ``after_save`` -- ``before_destroy`` -- ``around_destroy`` -- ``after_destroy`` - -Callbacks are available on any document, whether it is embedded within -another document or not. Note that to be efficient, Mongoid only invokes -the callback on the document that the persistence action was executed on. -This enables Mongoid to support large hierarchies and to handle optimized -atomic updates efficiently (without invoking callbacks throughout the document -hierarchy). - -Note that using callbacks for domain logic is a bad design practice, and can -lead to unexpected errors that are hard to debug when callbacks in -the chain halt execution. It is our recommendation to only use them -for cross-cutting concerns, like queueing up background jobs. - -.. code-block:: ruby - - class Article - include Mongoid::Document - field :name, type: String - field :body, type: String - field :slug, type: String - - before_create :send_message - - after_save do |document| - # Handle callback here. - end - - protected - def send_message - # Message sending code here. - end - end - -Callbacks are coming from Active Support, so you can use the new -syntax as well: - -.. code-block:: ruby - - class Article - include Mongoid::Document - field :name, type: String - - set_callback(:create, :before) do |document| - # Message sending code here. - end - end - - -Association Callbacks -===================== - -Mongoid has a set of callbacks that are specific to associations - these are: - -- ``after_add`` -- ``after_remove`` -- ``before_add`` -- ``before_remove`` - -Each time a document is added or removed from any of the following -associations, the respective callbacks are invoked: ``embeds_many``, -``has_many`` and ``has_and_belongs_to_many``. - -Association callbacks are specified as options on the respective association. -The document added/removed will be passed as the parameter to the specified -callback. Example: - -.. code-block:: ruby - - class Person - include Mongoid::Document - - has_many :posts, after_add: :send_email_to_subscribers - end - - def send_email_to_subscribers(post) - Notifications.new_post(post).deliver - end diff --git a/docs/reference/collection-configuration.txt b/docs/reference/collection-configuration.txt deleted file mode 100644 index 26bea0162b..0000000000 --- a/docs/reference/collection-configuration.txt +++ /dev/null @@ -1,107 +0,0 @@ -.. _collection_configuration: - -************************ -Collection Configuration -************************ - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Configuring a Document Collection -================================= - -You can specify collection options for documents using the ``store_in`` macro. -This macro accepts ``:collection_options`` argument, which can contain any collection -options that are supported by the driver. - -.. note:: - - In order to apply the options, the collection must be explicitly created up-front. - This should be done using :ref:`Collection Management Rake Task`. - -Please refer to `the driver collections page -`_ -for the more information about collection options. - -.. note:: - - Collection options depend on the driver version and MongoDB server version. - It is possible that some options, like time series collections, are not available - on older server versions. - -Time Series Collection ----------------------- - -.. code-block:: ruby - - class Measurement - include Mongoid::Document - - field :temperature, type: Integer - field :timestamp, type: Time - - store_in collection_options: { - time_series: { - timeField: "timestamp", - granularity: "minutes" - }, - expire_after: 604800 - } - end - - - -Capped Collections ------------------- - -.. code-block:: ruby - - class Name - include Mongoid::Document - - store_in collection_options: { - capped: true, - size: 1024 - } - end - -Set a Default Collation on a Collection ---------------------------------------- - -.. code-block:: ruby - - class Name - include Mongoid::Document - - store_in collection_options: { - collation: { - locale: 'fr' - } - } - end - -.. _collection-management-task: - -Collection Management Rake Task -=============================== - -If you specify collection options for a document, then the corresponding collection -must be explicitly created prior to use. To do so, use the provided -``db:mongoid:create_collections`` Rake task: - -.. code-block:: bash - - $ rake db:mongoid:create_collections - -The create collections command also works for just one model by running -in Rails console: - -.. code-block:: ruby - - # Create collection for Model - Model.create_collection diff --git a/docs/reference/compatibility.txt b/docs/reference/compatibility.txt deleted file mode 100644 index fa15c8fabb..0000000000 --- a/docs/reference/compatibility.txt +++ /dev/null @@ -1,470 +0,0 @@ -.. _compatibility: - -************* -Compatibility -************* - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Ruby MongoDB Driver Compatibility -================================= - -The following compatibility table specifies the versions of `Ruby driver for -MongoDB `_ -(the ``mongo`` gem) supported by the most recent patch releases of the -specified Mongoid versions. - -.. note:: - - Older versions of Mongoid within the same minor release may support older - driver versions. For example, Mongoid 7.0.5 supports driver versions 2.5 and - newer, whereas Mongoid 7.0.6 requires driver version 2.7 or newer. - -.. list-table:: - :header-rows: 1 - :stub-columns: 1 - :class: compatibility-large no-padding - - * - Mongoid - - Driver 2.19-2.18 - - Driver 2.17-2.10 - - Driver 2.9-2.7 - - * - 8.0 thru 9.0 - - |checkmark| - - - - - - * - 7.2 thru 7.5 - - |checkmark| - - |checkmark| - - - - * - 7.0 thru 7.1 - - |checkmark| - - |checkmark| - - |checkmark| - - -Ruby Compatibility -================== - -The following compatibility table specifies the versions of Ruby interpreters -supported by Mongoid. "D" in a column means support for that Ruby version -is deprecated. - -.. list-table:: - :header-rows: 1 - :stub-columns: 1 - :class: compatibility-large no-padding - - * - Mongoid - - Ruby 3.2 - - Ruby 3.1 - - Ruby 3.0 - - Ruby 2.7 - - Ruby 2.6 - - Ruby 2.5 - - Ruby 2.4 - - Ruby 2.3 - - Ruby 2.2 - - JRuby 9.4 - - JRuby 9.3 - - JRuby 9.2 - - * - 9.0 - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - - - - - - - - - - - |checkmark| - - - - - - * - 8.1 - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - - - - - - - - - - - |checkmark| - - - - * - 8.0 - - - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - - - - - - - - - - - |checkmark| - - - - * - 7.5 - - - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - D - - - - - - - - - - |checkmark| - - D - - * - 7.4 - - - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - - - - - - - - - - - |checkmark| - - * - 7.3 - - - - |checkmark| [#mongoid-7.3-ruby-3.0]_ - - |checkmark| [#mongoid-7.3-ruby-3.0]_ - - |checkmark| - - |checkmark| - - |checkmark| - - D - - D - - - - - - - - |checkmark| - - * - 7.2 - - - - |checkmark| [#mongoid-7.2-ruby-3.0]_ - - |checkmark| [#mongoid-7.2-ruby-3.0]_ - - |checkmark| - - |checkmark| - - |checkmark| - - D - - D - - - - - - - - |checkmark| - - * - 7.1 - - - - |checkmark| [#mongoid-7.1-ruby-3.0]_ - - |checkmark| [#mongoid-7.1-ruby-3.0]_ - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| [#ruby-2.4]_ - - |checkmark| - - - - - - - - |checkmark| - - * - 7.0 - - - - - - - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| [#ruby-2.4]_ - - |checkmark| - - |checkmark| [#ruby-2.2]_ - - - - - - |checkmark| - -.. [#mongoid-7.3-ruby-3.0] Mongoid version 7.3.2 or higher is required. - -.. [#mongoid-7.2-ruby-3.0] Mongoid version 7.2.5 or higher is required. - -.. [#mongoid-7.1-ruby-3.0] Mongoid version 7.1.10 or higher is required. - -.. [#ruby-2.4] Ruby version 2.4.1 or higher is required. - -.. [#ruby-2.2] Ruby version 2.2.2 or higher is required. - - -MongoDB Server Compatibility -============================ - -The following compatibility table specifies the recommended -version(s) of Mongoid for use with a specific version of MongoDB server. - -Note that in order to use features of a particular MongoDB server version, -both the driver and Mongoid must support that server version. -Please refer to `the driver compatibility page -`_ -for driver compatibility matrices. - -"D" in a column means support for that MongoDB server version is deprecated -and will be removed in a next version. - -.. list-table:: - :header-rows: 1 - :stub-columns: 1 - :class: compatibility-large no-padding - - * - Mongoid - - MongoDB 7.0 - - MongoDB 6.0 - - MongoDB 5.0 - - MongoDB 4.4 - - MongoDB 4.2 - - MongoDB 4.0 - - MongoDB 3.6 - - MongoDB 3.4 - - MongoDB 3.2 - - MongoDB 3.0 - - MongoDB 2.6 - - * - 8.0 thru 9.0 - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - - - - - - - - - * - 7.4 thru 7.5 - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - D - - D - - D - - D - - * - 7.0 thru 7.3 - - - - - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| - - D - - D - - D - - D - - -.. _rails-compatibility: - -Rails Compatibility -=================== - -The following compatibility table specifies which versions of Ruby on Rails -are supported by Mongoid. - -.. list-table:: - :header-rows: 1 - :stub-columns: 1 - :class: compatibility-large no-padding - - * - Mongoid - - Rails 7.1 - - Rails 7.0 - - Rails 6.1 - - Rails 6.0 - - Rails 5.2 - - Rails 5.1 - - * - 9.0 - - |checkmark| [#rails-7.1]_ - - |checkmark| - - |checkmark| - - |checkmark| - - - - - - * - 8.0 thru 8.1 - - |checkmark| [#rails-7.1]_ - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| [#rails-5-ruby-3.0]_ - - - - * - 7.5 - - - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| [#rails-5-ruby-3.0]_ - - D - - * - 7.4 - - - - |checkmark| - - |checkmark| - - |checkmark| - - |checkmark| [#rails-5-ruby-3.0]_ - - |checkmark| [#rails-5-ruby-3.0]_ - - * - 7.3 - - - - |checkmark| [#rails-7-Mongoid-7.3]_ - - |checkmark| - - |checkmark| - - |checkmark| [#rails-5-ruby-3.0]_ - - |checkmark| [#rails-5-ruby-3.0]_ - - * - 7.2 - - - - - - |checkmark| [#rails-6.1]_ - - |checkmark| - - |checkmark| [#rails-5-ruby-3.0]_ - - |checkmark| [#rails-5-ruby-3.0]_ - - * - 7.1 - - - - - - |checkmark| [#rails-6.1]_ - - |checkmark| - - |checkmark| - - |checkmark| - - * - 7.0 - - - - - - |checkmark| [#rails-6.1]_ - - |checkmark| [#rails-6]_ - - |checkmark| - - |checkmark| - -.. [#rails-5-ruby-3.0] Using Rails 5.x with Ruby 3 is not supported. - -.. [#rails-6] Rails 6.0 requires Mongoid 7.0.5 or later. - -.. [#rails-6.1] Rails 6.1 requires Mongoid 7.0.12, 7.1.7 or 7.2.1 in the - respective 7.0, 7.1 and 7.2 stable branches. - -.. [#rails-7-Mongoid-7.3] Rails 7.x requires Mongoid 7.3.4 or later. - -.. [#rails-7.1] Rails 7.1 requires Mongoid 8.0.7 or 8.1.3 in the respective - 8.0 and 8.1 stable branches. - -.. include:: /includes/unicode-checkmark.rst -.. include:: /includes/unicode-ballot-x.rst - -Rails Frameworks Support ------------------------- - -Ruby on Rails is comprised of a number of frameworks, which Mongoid attempts to -provide compatibility with wherever possible. - -Though Mongoid attempts to offer API compatibility with `Active Record `_, -libraries that depend directly on Active Record may not work as expected when -Mongoid is used as a drop-in replacement. - -.. note:: - - Mongoid can be used alongside Active Record within the same application without issue. - -.. list-table:: - :header-rows: 1 - :stub-columns: 1 - :class: compatibility-large no-padding - - * - Rails Framework - - Supported? - - * - ``ActionCable`` - - |checkmark| [#rails-actioncable-dependency]_ - - * - ``ActionMailbox`` - - |x| [#rails-activerecord-dependency]_ - - * - ``ActionMailer`` - - |checkmark| - - * - ``ActionPack`` - - |checkmark| - - * - ``ActionText`` - - |x| [#rails-activerecord-dependency]_ - - * - ``ActionView`` - - |checkmark| - - * - ``ActiveJob`` - - |checkmark| [#rails-activejob-dependency]_ - - * - ``ActiveModel`` - - |checkmark| [#rails-activemodel-dependency]_ - - * - ``ActiveStorage`` - - |x| [#rails-activerecord-dependency]_ - - * - ``ActiveSupport`` - - |checkmark| [#rails-activesupport-dependency]_ - -.. [#rails-actioncable-dependency] There is currently no MongoDB adapter for - ``ActionCable``, however any existing adapter (such as `Redis `_) - can be used successfully in conjunction with Mongoid models - -.. [#rails-activerecord-dependency] Depends directly on ``ActiveRecord`` - -.. [#rails-activemodel-dependency] ``Mongoid::Document`` includes ``ActiveModel::Model`` - and leverages ``ActiveModel::Validations`` for validations - -.. [#rails-activesupport-dependency] ``Mongoid`` requires ``ActiveSupport`` and - uses it extensively, including ``ActiveSupport::TimeWithZone`` for time handling. - - - -.. [#rails-activejob-dependency] Serialization of BSON & Mongoid objects works best - if you explicitly send ``BSON::ObjectId``'s as strings, and reconstitute them in the job: - - .. code-block:: ruby - - record = Model.find(...) - MyJob.perform_later(record._id.to_s) - - class MyJob < ApplicationJob - def perform(id_as_string) - record = Model.find(id_as_string) - # ... - end - end diff --git a/docs/reference/configuration.txt b/docs/reference/configuration.txt deleted file mode 100644 index 2d82faf24a..0000000000 --- a/docs/reference/configuration.txt +++ /dev/null @@ -1,1027 +0,0 @@ -.. _configuration: - -************* -Configuration -************* - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Mongoid is customarily configured through a ``mongoid.yml`` file that specifies -options and clients. The simplest configuration is as follows, which configures -Mongoid to talk to a MongoDB server at "localhost:27017" and use the database -named "mongoid". - -.. code-block:: yaml - - development: - clients: - default: - database: mongoid - hosts: - - localhost:27017 - -The top level key in the configuration file, ``development`` in the above -example, refers to the environment name which the application is executing in, -i.e. ``development``, ``test`` or ``production``. The third level key, -``default`` in the above example, refers to the Mongo client name. -Most applications will use a single client named ``default``. - - -Generating Default Configuration -================================ - -If you are using Ruby on Rails, you can have Mongoid generate a default -configuration file for you by running the following command: - -.. code-block:: bash - - rails g mongoid:config - -The configuration file will be placed in ``config/mongoid.yml``. An -initializer will also be created and placed in -``config/initializers/mongoid.rb``. It is recommended that all configuration -be specified in ``config/mongoid.yml``, but if you prefer, the ``mongoid.rb`` -initializer may also be used to set configuration options. Note, though, that -settings in ``mongoid.yml`` always take precedence over settings in the -initializer. - -If you are not using Ruby on Rails, you can copy the minimal configuration -given above and save it as ``config/mongoid.yml``. - - -Loading Mongoid Configuration -============================= - -If you are using Ruby on Rails, Mongoid configuration is automatically loaded -for the current environment as stored in ``Rails.env`` when the application -loads. - -You may need to configure the ORM for your application to be Mongoid by -adding the following to ``application.rb``: - -.. code-block:: ruby - - config.generators do |g| - g.orm :mongoid - end - -If you are not using Ruby on Rails, Mongoid configuration must be loaded -manually. This can be done via the ``Mongoid.load!`` method, which takes -the configuration file path as its argument, as follows: - -.. code-block:: ruby - - # Use automatically detected environment name - Mongoid.load!("path/to/your/mongoid.yml") - - # Specify environment name manually - Mongoid.load!("path/to/your/mongoid.yml", :production) - -When Mongoid is asked to automatically detect the environment name, -it does so by examining the following sources, in order: - -- If ``Rails`` top level constant is defined, ``Rails.env``. -- If ``Sinatra`` top level constant is defined, ``Sinatra::Base.environment``. -- The ``RACK_ENV`` environment variable. -- The ``MONGOID_ENV`` environment variable. - -It is also possible to configure Mongoid directly in Ruby, without using -a configuration file. This configuration style does not support the concept -of environments - whatever configuration is provided, it is applied to the -current environment - but it does support defining multiple clients. - -.. code-block:: ruby - - Mongoid.configure do |config| - config.clients.default = { - hosts: ['localhost:27017'], - database: 'my_db', - } - - config.log_level = :warn - end - -.. note:: - - Mongoid must be configured *before* any component of it is used or referenced. - Once a component is used or referenced, changing configuration may not apply - changes to already instantiated components. - - -.. _configuration-options: - -Mongoid Configuration Options -============================= - -The following annotated example ``mongoid.yml`` demonstrates how Mongoid -can be configured. - -Mongoid delegates to the Ruby driver for client configuration. Please review -`the driver documentation `_ -for details on driver options. - -.. code-block:: yaml - - development: - # Configure available database clients. (required) - clients: - # Defines the default client. (required) - default: - # Mongoid can connect to a URI accepted by the driver: - # uri: mongodb://user:password@mongodb.domain.com:27017/my_db_development - - # Otherwise define the parameters separately. - # This defines the name of the default database that Mongoid can connect to. - # (required). - database: my_db_development - # Provides the hosts the default client can connect to. Must be an array - # of host:port pairs. (required) - hosts: - - localhost:27017 - options: - # Note that all options listed below are Ruby driver client options (the mongo gem). - # Please refer to the driver documentation of the version of the mongo gem you are using - # for the most up-to-date list of options. - - # Change the default write concern. (default = { w: 1 }) - # write: - # w: 1 - - # Change the default read preference. Valid options for mode are: :secondary, - # :secondary_preferred, :primary, :primary_preferred, :nearest - # (default: primary) - # read: - # mode: :secondary_preferred - # tag_sets: - # - use: web - - # The name of the user for authentication. - # user: 'user' - - # The password of the user for authentication. - # password: 'password' - - # The user's database roles. - # roles: - # - 'dbOwner' - - # Change the default authentication mechanism. Valid options include: - # :scram, :scram256, :mongodb_cr, :mongodb_x509, :gssapi, :aws, :plain. - # MongoDB Server defaults to :scram, which will use "SCRAM-SHA-256" if available, - # otherwise fallback to "SCRAM-SHA-1" (:scram256 will always use "SCRAM-SHA-256".) - # This setting is handled by the MongoDB Ruby Driver. Please refer to: - # https://mongodb.com/docs/ruby-driver/current/reference/authentication/ - # auth_mech: :scram - - # The database or source to authenticate the user against. - # (default: the database specified above or admin) - # auth_source: admin - - # Force a the driver cluster to behave in a certain manner instead of auto- - # discovering. Can be one of: :direct, :replica_set, :sharded. Set to :direct - # when connecting to hidden members of a replica set. - # connect: :direct - - # Changes the default time in seconds the server monitors refresh their status - # via hello commands. (default: 10) - # heartbeat_frequency: 10 - - # The time in seconds for selecting servers for a near read preference. (default: 0.015) - # local_threshold: 0.015 - - # The timeout in seconds for selecting a server for an operation. (default: 30) - # server_selection_timeout: 30 - - # The maximum number of connections in the connection pool. (default: 5) - # max_pool_size: 5 - - # The minimum number of connections in the connection pool. (default: 1) - # min_pool_size: 1 - - # The time to wait, in seconds, in the connection pool for a connection - # to be checked in before timing out. (default: 5) - # wait_queue_timeout: 5 - - # The time to wait to establish a connection before timing out, in seconds. - # (default: 10) - # connect_timeout: 10 - - # How long to wait for a response for each operation sent to the - # server. This timeout should be set to a value larger than the - # processing time for the longest operation that will be executed - # by the application. Note that this is a client-side timeout; - # the server may continue executing an operation after the client - # aborts it with the SocketTimeout exception. - # (default: nil, meaning no timeout) - # socket_timeout: 5 - - # The name of the replica set to connect to. Servers provided as seeds that do - # not belong to this replica set will be ignored. - # replica_set: name - - # Compressors to use for wire protocol compression. (default is to not use compression) - # "zstd" requires zstd-ruby gem. "snappy" requires snappy gem. - # Refer to: https://www.mongodb.com/docs/ruby-driver/current/reference/create-client/#compression - # compressors: ["zstd", "snappy", "zlib"] - - # Whether to connect to the servers via ssl. (default: false) - # ssl: true - - # The certificate file used to identify the connection against MongoDB. - # ssl_cert: /path/to/my.cert - - # The private keyfile used to identify the connection against MongoDB. - # Note that even if the key is stored in the same file as the certificate, - # both need to be explicitly specified. - # ssl_key: /path/to/my.key - - # A passphrase for the private key. - # ssl_key_pass_phrase: password - - # Whether to do peer certification validation. (default: true) - # ssl_verify: true - - # The file containing concatenated certificate authority certificates - # used to validate certs passed from the other end of the connection. - # ssl_ca_cert: /path/to/ca.cert - - # Whether to truncate long log lines. (default: true) - # truncate_logs: true - - # Configure Mongoid-specific options. (optional) - options: - # Allow BSON::Decimal128 to be parsed and returned directly in - # field values. When BSON 5 is present and the this option is set to false - # (the default), BSON::Decimal128 values in the database will be returned - # as BigDecimal. - # - # @note this option only has effect when BSON 5+ is present. Otherwise, - # the setting is ignored. - # allow_bson5_decimal128: false - - # Application name that is printed to the MongoDB logs upon establishing - # a connection. Note that the name cannot exceed 128 bytes in length. - # It is also used as the database name if the database name is not - # explicitly defined. (default: nil) - # app_name: nil - - # When this flag is false, callbacks for embedded documents will not be - # called. This is the default in 9.0. - # - # Setting this flag to true restores the pre-9.0 behavior, where callbacks - # for embedded documents are called. This may lead to stack overflow errors - # if there are more than cicrca 1000 embedded documents in the root - # document's dependencies graph. - # See https://jira.mongodb.org/browse/MONGOID-5658 for more details. - # around_callbacks_for_embeds: false - - # Sets the async_query_executor for the application. By default the thread pool executor - # is set to `:immediate`. Options are: - # - # - :immediate - Initializes a single +Concurrent::ImmediateExecutor+ - # - :global_thread_pool - Initializes a single +Concurrent::ThreadPoolExecutor+ - # that uses the +async_query_concurrency+ for the +max_threads+ value. - # async_query_executor: :immediate - - # Mark belongs_to associations as required by default, so that saving a - # model with a missing belongs_to association will trigger a validation - # error. - # belongs_to_required_by_default: true - - # Set the global discriminator key. - # discriminator_key: "_type" - - # Raise an exception when a field is redefined. - # duplicate_fields_exception: false - - # Defines how many asynchronous queries can be executed concurrently. - # This option should be set only if `async_query_executor` is set - # to `:global_thread_pool`. - # global_executor_concurrency: nil - - # When this flag is true, any attempt to change the _id of a persisted - # document will raise an exception (`Errors::ImmutableAttribute`). - # This is the default in 9.0. Setting this flag to false restores the - # pre-9.0 behavior, where changing the _id of a persisted - # document might be ignored, or it might work, depending on the situation. - # immutable_ids: true - - # Include the root model name in json serialization. - # include_root_in_json: false - - # # Include the _type field in serialization. - # include_type_for_serialization: false - - # Whether to join nested persistence contexts for atomic operations - # to parent contexts by default. - # join_contexts: false - - # When this flag is false (the default as of Mongoid 9.0), a document that - # is created or loaded will remember the storage options that were active - # when it was loaded, and will use those same options by default when - # saving or reloading itself. - # - # When this flag is true you'll get pre-9.0 behavior, where a document will - # not remember the storage options from when it was loaded/created, and - # subsequent updates will need to explicitly set up those options each time. - # - # For example: - # - # record = Model.with(collection: 'other_collection') { Model.first } - # - # This will try to load the first document from 'other_collection' and - # instantiate it as a Model instance. Pre-9.0, the record object would - # not remember that it came from 'other_collection', and attempts to - # update it or reload it would fail unless you first remembered to - # explicitly specify the collection every time. - # - # As of Mongoid 9.0, the record will remember that it came from - # 'other_collection', and updates and reloads will automatically default - # to that collection, for that record object. - # legacy_persistence_context_behavior: false - - # When this flag is false, a document will become read-only only once the - # #readonly! method is called, and an error will be raised on attempting - # to save or update such documents, instead of just on delete. When this - # flag is true, a document is only read-only if it has been projected - # using #only or #without, and read-only documents will not be - # deletable/destroyable, but they will be savable/updatable. - # When this feature flag is turned on, the read-only state will be reset on - # reload, but when it is turned off, it won't be. - # legacy_readonly: false - - # The log level. - # - # It must be set prior to referencing clients or Mongo.logger, - # changes to this option are not be propagated to any clients and - # loggers that already exist. - # - # Additionally, only when the clients are configured via the - # configuration file is the log level given by this option honored. - # log_level: :info - - # Store BigDecimals as Decimal128s instead of strings in the db. - # map_big_decimal_to_decimal128: true - - # Preload all models in development, needed when models use inheritance. - # preload_models: false - - # When this flag is true, callbacks for every embedded document will be - # called only once, even if the embedded document is embedded in multiple - # documents in the root document's dependencies graph. - # This is the default in 9.0. Setting this flag to false restores the - # pre-9.0 behavior, where callbacks are called for every occurrence of an - # embedded document. The pre-9.0 behavior leads to a problem that for multi - # level nested documents callbacks are called multiple times. - # See https://jira.mongodb.org/browse/MONGOID-5542 - # prevent_multiple_calls_of_embedded_callbacks: true - - # Raise an error when performing a #find and the document is not found. - # raise_not_found_error: true - - # Raise an error when defining a scope with the same name as an - # existing method. - # scope_overwrite_exception: false - - # Return stored times as UTC. - # use_utc: false - - # Configure Driver-specific options. (optional) - driver_options: - # When this flag is off, an aggregation done on a view will be executed over - # the documents included in that view, instead of all documents in the - # collection. When this flag is on, the view filter is ignored. - # broken_view_aggregate: true - - # When this flag is set to false, the view options will be correctly - # propagated to readable methods. - # broken_view_options: true - - # When this flag is set to true, the update and replace methods will - # validate the parameters and raise an error if they are invalid. - # validate_update_replace: false - - -.. _load-defaults: - -Version Based Defaults -====================== - -Mongoid supports setting the configuration options to the defaults for specific -versions. This is useful for upgrading to a new Mongoid version. When upgrading -your Mongoid version, the following should be set on ``Mongoid::Config``: - -.. code:: ruby - - Mongoid.configure do |config| - config.load_defaults - end - -This way, when upgrading to a new version of Mongoid, your code will run with -the configuration options from the previous version of Mongoid. Then, -one-by-one, you can change the feature flags for the new version, and test that -your code still acts as expected. Once all of the new feature flags have been -accounted for, the call to ``load_defaults`` may be changed to take in the *new* -version, and all of the changed feature flags may be removed. - -For example, suppose we're upgrading from 7.5 to 8.0. Between these two versions, -two feature flags were added: ``legacy_attributes`` and ``map_big_decimal_to_decimal128``. -Before upgrading to Mongoid 8, add the following to your ``Mongoid::Config``: - -.. code:: ruby - - Mongoid.configure do |config| - config.load_defaults 7.5 - end - -After upgrading to Mongoid 8.0 in your ``Gemfile``, any feature flags will -remain set to their 7.5 default behavior: ``legacy_attributes: true, -map_big_decimal_to_decimal128: false``. You may then flip these feature flags -one-by-one to their 8.0 behavior: - -.. code:: ruby - - Mongoid.configure do |config| - config.load_defaults 7.5 - config.legacy_attributes = false - # config.map_big_decimal_to_decimal128 = true - end - -We recommend do these one at a time, so in the example above we leave the -second flag commented out. After verifying your code works as expected with the -``legacy_attributes`` flag turned off, the ``map_big_decimal_to_decimal128`` -setting can be uncommented. Once that functionality is verified as well, both -of those lines can be removed and the ``load_defaults`` replaced with: - -.. code:: ruby - - Mongoid.configure do |config| - config.load_defaults 8.0 - end - - -ERb Preprocessing -================= - -When loading a configuration file, Mongoid processes it with ERb before -parsing it as YAML. This allows, for example, constructing the contents of -the configuration file at runtime based on environment variables: - -.. code-block:: yaml - - development: - clients: - default: - uri: "<%= ENV['MONGODB_URI'] %>" - -.. note:: - - When outputting values from ERb, ensure the values are valid YAML and - escape them as needed. - -.. note:: - - Since ERb rendering is performed prior to YAML parsing, all ERb directives - in the configuration file are evaluated, including those occurring in YAML - comments. - -Logging -======= - -When configuring logging, it is important to keep in mind that Mongoid -provides a model layer on top of the MongoDB Ruby driver, and the driver -dispatches the CRUD operations to the MongoDB deployment. Therefore, some -of the logging output in an application using Mongoid comes from Mongoid -itself, and some comes from the driver. - -The Mongo client is a Ruby driver client instance, therefore -the logger of a Mongo client is the Ruby driver logger, not the Mongoid -logger. In other words: - -.. code-block:: ruby - - # Ruby driver logger, not Mongoid logger - Mongoid.client(:default).logger - -Depending on whether Mongoid is used in a Ruby on Rails application, and how -both Mongoid and Ruby driver are configured, they may use the same logger -instance or different instances, potentially with different configurations. - -In Ruby on Rails Application ----------------------------- - -When used in a Ruby on Rails application, Mongoid by default inherits -the logger and the log level from Rails, and sets the driver's logger -to the same logger instance: - -.. code-block:: ruby - - Rails.logger === Mongoid.logger - # => true - - Mongoid.logger === Mongo::Logger.logger - # => true - -To change the log level, use `standard Rails configuration -`_. -Place the following in one of environment configuration files, such as -``config/environments/production.rb``: - -.. code-block:: ruby - - Rails.application.configure do - config.log_level = :debug - end - -.. note:: - - The ``log_level`` Mongoid configuration option is not used when Mongoid operates - in a Rails application, because Mongoid inherits Rails' log level in this case. - -To configure either Mongoid or driver logger differently from the Rails logger, -use an initializer as follows: - -.. code-block:: ruby - - Rails.application.configure do - config.after_initialize do - # Change Mongoid log destination and/or level - Mongoid.logger = Logger.new(STDERR).tap do |logger| - logger.level = Logger::DEBUG - end - - # Change driver log destination and/or level - Mongo::Logger.logger = Logger.new(STDERR).tap do |logger| - logger.level = Logger::DEBUG - end - end - end - -.. note:: - - There is currently no provision in the Ruby standard library ``Logger`` - to return the log device (i.e. the ``IO`` object) that a logger is using. - To have, for example, Mongoid and/or the Ruby driver log to the - standard Rails log file (e.g. ``log/development.log``) but with a - different level from standard Rails logger (``Rails.logger``), the - file must be opened separately and the resulting ``IO`` object passed to - the ``Logger`` constructor. - -.. note:: - - Since by default Mongoid sets its own logger and the driver's logger to the - same instance as the Rails logger, modifying any of the instances affects - all of them. For example the following changes log level for all three - loggers, unless the application assigned a separate ``Logger`` instance - to ``Mongo::Logger.logger`` as described above: - - .. code-block:: ruby - - Mongoid::Logger.logger.level = Logger::DEBUG - -Standalone ----------- - -When not loaded in a Ruby on Rails application, Mongoid respects the -``log_level`` top level configuration option. It can be given in the -configuration file as follows: - -.. code-block:: yaml - - development: - clients: - default: - # ... - options: - log_level: :debug - -... or when configuring Mongoid inline: - -.. code-block:: ruby - - Mongoid.configure do |config| - config.log_level = :debug - end - -The default log destination in Mongoid 7.1 and higher is standard error. -The default log destination in Mongoid 7.0 and lower is standard output. -To change the log destination, create a new logger instance as follows: - -.. code-block:: ruby - - Mongoid.logger = Logger.new(STDERR).tap do |logger| - logger.level = Logger::DEBUG - end - -To change the Ruby driver log level or destination: - -.. code-block:: ruby - - Mongo::Logger.logger = Logger.new(STDERR).tap do |logger| - logger.level = Logger::DEBUG - end - -To set the driver logger to be the same as the Mongoid logger: - -.. code-block:: ruby - - Mongo::Logger.logger = Mongoid.logger - -.. note:: - - Mongoid does not alter the driver's logger when running in - standalone mode. - -.. _time-zones: - -Time Zones -========== - -Mongoid uses ActiveSupport's time zone functionality, which is far -more robust than Ruby's standard library. Importantly, ActiveSupport -allows configuration of ``Time.zone``, a thread-global variable which -provides context for working with date and time values. - -While a thorough treatment of time zones in Ruby is outside the scope -of this tutorial, the easiest and most reliable way of achieving correct -time zone handling is as follows: - -1. Set the operating system's time zone to UTC. For example, on Linux: - -.. code-block:: bash - - cp /usr/share/zoneinfo/UTC /etc/localtime - -2. Set your application default time zone to UTC: - -.. code-block:: ruby - - # If using Rails, in application.rb: - class Application < Rails::Application - config.time_zone = 'UTC' - end - - # If not using Rails: - Time.zone = 'UTC' - -3. In each controller and job class, set the appropriate time zone in a - ``before_filter`` at the earliest possible stage. As an example, - if each user of your application can set their own time zone, - you may wish to do: - -.. code-block:: ruby - - class ApplicationController < ActionController::Base - before_filter :fetch_user, - :set_time_zone - - def set_time_zone - Time.zone = @user.time_zone - end - end - -4. From here, you may work with times naturally in the local time zone. - For example, in a view: - -.. code-block:: ruby - - Turned into a pumpkin after <%= cinderella.updated_at.seconds_after_midnight %> seconds! - -5. Use ActiveSupport methods instead of the Ruby standard library. - - - ``Time.zone.now`` or ``Time.current` instead of ``Time.now`` - - ``Date.current`` instead of ``Date.today`` - - Critically, note that the latter Ruby standard library methods reference - your system time zone (e.g. UTC) and not the value of ``Time.zone``. - As it is very easy to mistake these similarly named methods, we recommend to - use `Rubocop's Rails/TimeZone cop - `_ in your CI. - -Setting time zone on data loaded from MongoDB ---------------------------------------------- - -MongoDB stores all times in UTC without time zone information. -Mongoid models load and returns time values as instances of -``ActiveSupport::TimeWithZone``. You may set the ``use_utc`` option -to control how Mongoid sets the time zone when loading from the database: - -- If false (default), Mongoid will use ``Time.zone`` to set the time - zone of time values are loaded from database. -- If true, Mongoid will always set the time zone as UTC on loaded - time values. - -``use_utc`` only affects how data is loaded, and does not affect -how data is persisted. For example, if you assign a ``Time`` or -``ActiveSupport::TimeWithZone`` instance to a time field, the time -zone information of the assigned instance always will be used -irrespective of the ``use_utc`` setting. Alternatively, if you -assign a string value to a time field, any time zone information -in the string will be used if present. If the string does not include -time zone information it will be parsed according to ``Time.zone``. -To illustrate: - -.. code-block:: ruby - - Time.use_zone("Asia/Kolkata") do - - # String does not include time zone, so "Asia/Kolkata" will be used - ghandi.born_at = "1869-10-02 7:10 PM" - - # Time zone in string (-0600) will be used - amelia.born_at = "1897-07-24 11:30 -0600" - end - - -Configuring ``SSLContext`` -========================== -It may be desirable to further configure TLS options in your application, for -example by enabling or disabling certain ciphers. - -This can be done by setting TLS context hooks on the Ruby driver -- TLS context -hooks are user-provided ``Proc``\(s) that will be invoked before any TLS socket -connection in the driver and can be used to modify the underlying -``OpenSSL::SSL::SSLContext`` object used by the socket. - -To set TLS context hooks, add ``Proc``\(s) to the ``Mongo.tls_context_hooks`` -array. This can be done in an initializer. The example below adds a hook -that only enables the "AES256-SHA" cipher. - -.. code-block:: ruby - - Mongo.tls_context_hooks.push( - Proc.new { |context| - context.ciphers = ["AES256-SHA"] - } - ) - - # Only the AES256-SHA cipher will be enabled from this point forward - -Every ``Proc`` in ``Mongo.tls_context_hooks`` will be passed an -``OpenSSL::SSL::SSLContext`` object as its sole argument. These procs will -be executed sequentially during socket creation. - -.. warning:: - - TLS context hooks are global and will affect all ``Mongo::Client`` instances - in an application. - -For more information about TLS context hooks, including best practices for -assigning and removing them, see `the Ruby driver documentation `_. - - -Network Compression -=================== - -Mongoid supports compression of messages to and from MongoDB servers. This functionality is provided by -the Ruby driver, which implements the three algorithms that are supported by MongoDB servers: - -- `Snappy `_: ``snappy`` compression - can be used when connecting to MongoDB servers starting with the 3.4 release, - and requires the `snappy `_ library to be - installed. -- `Zlib `_: ``zlib`` compression can be used when - connecting to MongoDB servers starting with the 3.6 release. -- `Zstandard `_: ``zstd`` compression can be - used when connecting to MongoDB servers starting with the 4.2 release, and - requires the `zstd-ruby `_ library to - be installed. - -To use wire protocol compression, configure the Ruby driver options within ``mongoid.yml``: - -.. code-block:: yaml - - development: - # Configure available database clients. (required) - clients: - # Define the default client. (required) - default: - # ... - options: - # These options are Ruby driver options, documented in - # https://mongodb.com/docs/ruby-driver/current/reference/create-client/ - # ... - # Compressors to use. (default is to not use compression) - # Valid values are zstd, zlib or snappy - or any combination of the three - compressors: ["zstd", "snappy"] - -If no compressors are explicitly requested, the driver will not use compression, -even if the required dependencies for one or more compressors are present on the -system. - -The driver chooses the first compressor of the ones requested that is also supported -by the server. The ``zstd`` compressor is recommended as it produces the highest -compression at the same CPU consumption compared to the other compressors. - -For maximum server compatibility all three compressors can be specified, e.g. -as ``compressors: ["zstd", "snappy", "zlib"]``. - - -Client-Side Encryption -====================== - -When loading the configuration file, Mongoid permits the file to contain -``BSON::Binary`` instances which are used for specifying ``keyId`` in -the schema map for `client-side encryption -`_, -as the following example shows: - -.. code-block:: yaml - - development: - clients: - default: - database: blog_development - hosts: [localhost:27017] - options: - auto_encryption_options: - key_vault_namespace: 'keyvault.datakeys' - kms_providers: - local: - key: "z7iYiYKLuYymEWtk4kfny1ESBwwFdA58qMqff96A8ghiOcIK75lJGPUIocku8LOFjQuEgeIP4xlln3s7r93FV9J5sAE7zg8U" - schema_map: - blog_development.comments: - properties: - message: - encrypt: - keyId: - - !ruby/object:BSON::Binary - data: !binary |- - R/AgNcxASFiiJWKXqWGo5w== - type: :uuid - bsonType: "string" - algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" - bsonType: "object" - - -Usage with Forking Servers -========================== - -When using Mongoid with a forking web server such as Puma, or any application -that otherwise forks to spawn child processes, special considerations apply. - -If possible, we recommend to not perform any MongoDB operations in the parent -process prior to forking, which will avoid any forking-related pitfalls. - -A detailed technical explanation of how the Mongo Ruby Driver handles forking -is given in the `driver's "Usage with Forking Servers" documentation -`. -In a nutshell, to avoid various connection errors such as ``Mongo::Error::SocketError`` -and ``Mongo::Error::NoServerAvailable``, you must do the following: - -1. Disconnect MongoDB clients in the parent Ruby process immediately *before* - forking using ``Mongoid.disconnect_clients``. This ensures the parent and child - process do not accidentally reuse the same sockets and have I/O conflicts. - Note that ``Mongoid.disconnect_clients`` does not disrupt any in-flight - MongoDB operations, and will automatically reconnect when you perform new - operations. -2. Reconnect your MongoDB clients in the child Ruby process immediately *after* - forking using ``Mongoid.reconnect_clients``. This is required to respawn - the driver's monitoring threads in the child process. - -Most web servers provide hooks that can be used by applications to -perform actions when the worker processes are forked. The following -are configuration examples for several common Ruby web servers. - -Puma ----- - -Use the ``on_worker_boot`` hook to reconnect clients in the workers and -the ``before_fork`` and ``on_refork`` hooks to close clients in the -parent process (`Puma documentation `_). - -.. code-block:: ruby - - # config/puma.rb - - # Runs in the Puma master process before it forks a child worker. - before_fork do - Mongoid.disconnect_clients - end - - # Required when using Puma's fork_worker option. Runs in the - # child worker 0 process before it forks grandchild workers. - on_refork do - Mongoid.disconnect_clients - end - - # Runs in each Puma child process after it forks from its parent. - on_worker_boot do - Mongoid.reconnect_clients - end - -Unicorn -------- - -Use the ``after_fork`` hook to reconnect clients in the workers and -the ``before_fork`` hook to close clients in the parent process -(`Unicorn documentation `_): - -.. code-block:: ruby - - # config/unicorn.rb - - before_fork do |_server, _worker| - Mongoid.disconnect_clients - end - - after_fork do |_server, _worker| - Mongoid.reconnect_clients - end - -Passenger ---------- - -Use the ``starting_worker_process`` hook to reconnect clients in the workers -(`Passenger documentation -`_). -Passenger does not appear to have a hook that is invoked in the parent process -before the workers are forked. - -.. code-block:: ruby - - if defined?(PhusionPassenger) - PhusionPassenger.on_event(:starting_worker_process) do |forked| - Mongoid.reconnect_clients if forked - end - end - - -.. _query-cache-middleware: - -Query Cache Middleware -====================== - -Enabling Query Cache for Rack Web Requests ------------------------------------------- - -The MongoDB Ruby Driver provides a Rack middleware which enables the :ref:`Query Cache -` for the duration of each web request. Below is an example of -how to enable the Query Cache Middleware in a Ruby on Rails application: - -.. code-block:: ruby - - # config/application.rb - - # Add Mongo::QueryCache::Middleware at the bottom of the middleware stack - # or before other middleware that queries MongoDB. - config.middleware.use Mongo::QueryCache::Middleware - -Please refer to the `Rails on Rack guide -`_ -for more information about using Rack middleware in Rails applications. - -Enabling Query Cache for ActiveJob ----------------------------------- - -The MongoDB Ruby Driver also provides Query Cache middleware for ActiveJob. -You may enable it for all jobs in an initializer: - -.. code-block:: ruby - - # config/initializers/active_job.rb - - # Enable Mongo driver query cache for ActiveJob - ActiveSupport.on_load(:active_job) do - include Mongo::QueryCache::Middleware::ActiveJob - end - -Or for a specific job class: - -.. code-block:: ruby - - class MyJob < ActiveJob::Base - include Mongo::QueryCache::Middleware::ActiveJob - end - - -Development Configuration -========================= - -Driver's default configuration is suitable for production deployment. -In development, some settings can be adjusted to provide a better developer -experience. - -- ``:server_selection_timeout``: set this to a low value (e.g., ``1``) - if your MongoDB server is running locally and you start it manually. A low - server selection timeout will cause the driver to fail quickly when there is - no server running. - -Sample recommended development configuration: - -.. code-block:: yaml - - development: - clients: - default: - database: mongoid - hosts: - - localhost:27017 - options: - server_selection_timeout: 1 diff --git a/docs/reference/crud.txt b/docs/reference/crud.txt deleted file mode 100644 index ff70fa6f5f..0000000000 --- a/docs/reference/crud.txt +++ /dev/null @@ -1,1074 +0,0 @@ -.. _crud: - -*************** -CRUD Operations -*************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -Saving Documents -================ - -Mongoid supports all expected CRUD operations for those familiar with other -Ruby mappers like Active Record or Data Mapper. What distinguishes Mongoid -from other mappers for MongoDB is that the general persistence operations -perform atomic updates on only the fields that have changed instead of -writing the entire document to the database each time. - -The persistence sections will provide examples on what database operation is -performed when executing the documented command. - -Standard --------- - -Mongoid's standard persistence methods come in the form of common methods you -would find in other mapping frameworks. The following table shows all standard -operations with examples. - -.. list-table:: - :header-rows: 1 - :widths: 30 60 - - * - Operation - - Example - - * - ``Model#attributes`` - - *Returns the document's attributes as a ``Hash`` with string keys, and - its values in Mongoized form (i.e. the way they are stored in the db).* - - *The attributes hash also contains the attributes of all embedded - documents, as well as their embedded documents, etc. If an embedded - association is empty, its key will not show up in the returned hash.* - - - - .. code-block:: ruby - - person = Person.new(first_name: "Heinrich", last_name: "Heine") - - person.attributes - # => { "_id" => BSON::ObjectId('633467d03282a43784c2d56e'), "first_name" => "Heinrich", "last_name" => "Heine" } - - * - ``Model.create!`` - - *Insert a document or multiple documents into the database, raising an - error if a validation or server error occurs.* - - *Pass a hash of attributes to create one document with the specified - attributes, or an array of hashes to create multiple documents. - If a single hash is passed, the corresponding document is returned. - If an array of hashes is passed, an array of documents corresponding - to the hashes is returned.* - - *If a block is given to* ``create!`` *, it will be invoked with each - document as the argument in turn prior to attempting to save that - document.* - - *If there is a problem saving any of the documents, such as - a validation error or a server error, an exception is raised - and, consequently, none of the documents are returned. - However, if an array of hashes was passed and previous documents were - successfully saved, those documents will remain in the database.* - - - .. code-block:: ruby - - Person.create!( - first_name: "Heinrich", - last_name: "Heine" - ) # => Person instance - - Person.create!([ - { first_name: "Heinrich", last_name: "Heine" }, - { first_name: "Willy", last_name: "Brandt" } - ]) # => Array of two Person instances - - Person.create!(first_name: "Heinrich") do |doc| - doc.last_name = "Heine" - end # => Person instance - - * - ``Model.create`` - - *Instantiate a document or multiple documents and, if validations pass, - insert them into the database.* - - ``create`` *is similar to* ``create!`` *but does not raise - exceptions on validation errors. It still raises errors on server - errors, such as trying to insert a document with an* ``_id`` *that - already exists in the collection.* - - *If any validation errors are encountered, the respective document - is not inserted but is returned along with documents that were inserted. - Use* ``persisted?`` *,* ``new_record?`` *or* ``errors`` *methods - to check which of the returned documents were inserted into the - database.* - - - .. code-block:: ruby - - Person.create( - first_name: "Heinrich", - last_name: "Heine" - ) # => Person instance - - Person.create([ - { first_name: "Heinrich", last_name: "Heine" }, - { first_name: "Willy", last_name: "Brandt" } - ]) # => Array of two Person instances - - Person.create(first_name: "Heinrich") do |doc| - doc.last_name = "Heine" - end # => Person instance - - class Post - include Mongoid::Document - - validates_uniqueness_of :title - end - - posts = Post.create([{title: "test"}, {title: "test"}]) - # => array of two Post instances - posts.map { |post| post.persisted? } # => [true, false] - - * - ``Model#save!`` - - *Save the changed attributes to the database atomically, or insert the document if - new. Raises an exception if validations fail or there is a server error.* - - *Returns true if the changed attributes were saved, raises an exception otherwise.* - - - .. code-block:: ruby - - person = Person.new( - first_name: "Heinrich", - last_name: "Heine" - ) - person.save! - - person.first_name = "Christian Johan" - person.save! - - * - ``Model#save`` - - *Save the changed attributes to the database atomically, or insert the document - if new.* - - *Returns true if the changed attributes were saved. Returns false - if there were any validation errors. Raises an exception if - the document passed validation but there was a server error during - the save.* - - *Pass* ``validate: false`` *option to bypass validations.* - - *Pass* ``touch: false`` *option to ignore the updates to the updated_at - field. If the document being save has not been previously persisted, - this option is ignored and the created_at and updated_at fields will be - updated with the current time.* - - - .. code-block:: ruby - - person = Person.new( - first_name: "Heinrich", - last_name: "Heine" - ) - person.save - person.save(validate: false) - person.save(touch: false) - - person.first_name = "Christian Johan" - person.save - - * - ``Model#update_attributes`` - - *Update the document attributes in the database. Will return true if validation passed, - false if not.* - - - .. code-block:: ruby - - person.update_attributes( - first_name: "Jean", - last_name: "Zorg" - ) - - * - ``Model#update_attributes!`` - - *Update the document attributes in the database and raise an error if validation failed.* - - - .. code-block:: ruby - - person.update_attributes!( - first_name: "Leo", - last_name: "Tolstoy" - ) - - * - ``Model#update_attribute`` - - *Update a single attribute, bypassing validations.* - - - .. code-block:: ruby - - person.update_attribute(:first_name, "Jean") - - * - ``Model#upsert`` - - *Performs a MongoDB replace with upsert on the document. If the document - exists in the database and the* ``:replace`` *option is set to true, it - will get overwritten with the current document in the application (any - attributes present in the database but not in the application's document - instance will be lost). If the* ``:replace`` *option is false (default), - the document will be updated, and any attributes not in the application's - document will be maintained. - If the document does not exist in the database, it will be inserted. - Note that this only runs the* ``{before|after|around}_upsert`` *callbacks.* - - - .. code-block:: ruby - - person = Person.new( - first_name: "Heinrich", - last_name: "Heine" - ) - person.upsert - person.upsert(replace: true) - - * - ``Model#touch`` - - *Update the document's updated_at timestamp, optionally with one extra - provided time field. This will cascade the touch to all* - ``belongs_to`` *associations of the document with the option set. - This operation skips validations and callbacks.* - - *Attempting to touch a destroyed document will raise* ``FrozenError``, - *same as if attempting to update an attribute on a destroyed - document.* - - - .. code-block:: ruby - - person.touch - person.touch(:audited_at) - - * - ``Model#delete`` - - *Deletes the document from the database without running callbacks.* - - *If the document is not persisted, Mongoid will attempt to delete from - the database any document with the same* ``_id``. - - - .. code-block:: ruby - - person.delete - - person = Person.create!(...) - unsaved_person = Person.new(id: person.id) - unsaved_person.delete - person.reload - # raises Mongoid::Errors::DocumentNotFound because the person was deleted - - * - ``Model#destroy`` - - *Deletes the document from the database while running destroy callbacks.* - - *If the document is not persisted, Mongoid will attempt to delete from - the database any document with the same* ``_id``. - - - .. code-block:: ruby - - person.destroy - - person = Person.create!(...) - unsaved_person = Person.new(id: person.id) - unsaved_person.destroy - person.reload - # raises Mongoid::Errors::DocumentNotFound because the person was deleted - - * - ``Model.delete_all`` - - *Deletes all documents from the database without running any callbacks.* - - - .. code-block:: ruby - - Person.delete_all - - * - ``Model.destroy_all`` - - *Deletes all documents from the database while running callbacks. This is a - potentially expensive operation since all documents will be loaded into memory.* - - - .. code-block:: ruby - - Person.destroy_all - -Mongoid provides the following persistence-related attributes: - -.. list-table:: - :header-rows: 1 - :widths: 30 60 - - * - Attribute - - Example - - - * - ``Model#new_record?`` - - *Returns* ``true`` *if the model instance has not yet been saved - to the database. Opposite of* ``persisted?`` - - - .. code-block:: ruby - - person = Person.new( - first_name: "Heinrich", - last_name: "Heine" - ) - person.new_record? # => true - person.save! - person.new_record? # => false - - * - ``Model#persisted?`` - - *Returns* ``true`` *if the model instance has been saved - to the database. Opposite of* ``new_record?`` - - - .. code-block:: ruby - - person = Person.new( - first_name: "Heinrich", - last_name: "Heine" - ) - person.persisted? # => false - person.save! - person.persisted? # => true - - -Atomic ------- - -Mongoid exposes :manual:`MongoDB update operators ` -as methods on Mongoid documents. When these methods are used, callbacks are -not invoked and validations are not performed. The supported update operators -are: - -.. list-table:: - :header-rows: 1 - :widths: 30 60 - - * - Operation - - Example - - * - ``Model#add_to_set`` - - *Performs an atomic $addToSet on the field.* - - - .. code-block:: ruby - - person.add_to_set(aliases: "Bond") - - * - ``Model#bit`` - - *Performs an atomic $bit on the field.* - - - .. code-block:: ruby - - person.bit(age: { and: 10, or: 12 }) - - * - ``Model#inc`` - - *Performs an atomic $inc on the field.* - - - .. code-block:: ruby - - person.inc(age: 1) - - * - ``Model#pop`` - - *Performs an atomic $pop on the field.* - - - .. code-block:: ruby - - person.pop(aliases: 1) - - * - ``Model#pull`` - - *Performs an atomic $pull on the field.* - - - .. code-block:: ruby - - person.pull(aliases: "Bond") - - * - ``Model#pull_all`` - - *Performs an atomic $pullAll on the field.* - - - .. code-block:: ruby - - person.pull_all(aliases: [ "Bond", "James" ]) - - * - ``Model#push`` - - *Performs an atomic $push on the field.* - - - .. code-block:: ruby - - person.push(aliases: ["007","008"]) - - * - ``Model#rename`` - - *Performs an atomic $rename on the field.* - - - .. code-block:: ruby - - person.rename(bday: :dob) - - * - ``Model#set`` - - *Updates an attribute on the model instance and, if the instance - is already persisted, performs an atomic $set on the field, bypassing - validations.* - - ``set`` *can also deeply set values on Hash fields.* - - ``set`` *can also deeply set values on* ``embeds_one`` *associations. - If such an association's document is nil, one will be created prior - to the update.* - - ``set`` *should not be used with* ``has_one`` *associations, as it - does not correctly work in such cases.* - - - - .. code-block:: ruby - - person = Person.create!(name: "Ricky Bobby") - person.set(name: "Tyler Durden") # updates name in the database - - - person = Person.new - person.set(name: "Tyler Durden") # does not write to database - person.name # => "Tyler Durden" - person.persisted? # => true - - - class Post - include Mongoid::Document - - field :metadata, type: Hash - end - - post = Post.create! - post.set('metadata.published_at' => Time.now) - post.metadata['published_at'] # => Time instance - - post.set('metadata.approved.today' => true) - post.metadata['approved'] # => {'today' => true} - - - class Flight - include Mongoid::Document - - embeds_one :plan - end - - class Plan - include Mongoid::Document - - embedded_in :flight - - field :route, type: String - end - - flight = Flight.create! - flight.plan # => nil - flight.set('plan.route', 'test route') - flight.plan # => Plan instance - flight.plan.route # => "test route" - - - * - ``Model#unset`` - - *Performs an atomic $unset on the field.* - - - .. code-block:: ruby - - person.unset(:name) - -Note that, because these methods skip validations, it is possible to both -save invalid documents into the database and end up with invalid documents -in the application (which would subsequently fail to save via a ``save`` -call due to the failing validations). - - -.. _atomic-operation-grouping: - -Atomic Operation Grouping -````````````````````````` - -Atomic operations may be grouped together using the ``#atomically`` method -on a document. All operations inside the block given to ``#atomically`` -are sent to the cluster in a single atomic command. For example: - -.. code-block:: ruby - - person.atomically do - person.inc(age: 1) - person.set(name: 'Jake') - end - -``#atomically`` blocks may be nested. The default behavior is to write -changes performed by each block as soon as the block ends: - -.. code-block:: ruby - - person.atomically do - person.atomically do - person.inc(age: 1) - person.set(name: 'Jake') - end - raise 'An exception' - # name and age changes are still persisted - end - -This behavior can be changed by specifying the ``join_context: true`` option -to ``#atomically``, or globally by setting the ``join_contexts`` -:ref:`configuration option ` to ``true``. When -context joining is enabled, nested ``#atomically`` blocks are joined with -the outer blocks, and only the outermost block (or the first block where -``join_contexts`` is false) actually writes changes to the cluster. -For example: - -.. code-block:: ruby - - person.atomically do - person.atomically(join_context: true) do - person.inc(age: 1) - person.set(name: 'Jake') - end - raise 'An exception' - # name and age changes are not persisted - end - -The context joining behavior can be enabled globally by default by setting -``join_context`` option in Mongoid configuration. In this case specifying -``join_context: false`` on an ``#atomically`` block can be used to -obtain the independent persistence context behavior. - -If an exception is raised in an ``#atomically`` block which has not yet -persisted its changes to the cluster, any pending attribute changes on -Mongoid models are reverted. For example: - -.. code-block:: ruby - - person = Person.new(name: 'Tom') - begin - person.atomically do - person.inc(age: 1) - person.set(name: 'Jake') - person.name # => 'Jake' - raise 'An exception' - end - rescue Exception - person.name # => 'Tom' - end - -Atomic operations described in this section apply to one document at a time, -therefore nesting ``#atomically`` blocks invoked on multiple documents does -not make changes to the different documents be persisted atomically together. -However, MongoDB offers :ref:`multi-document transactions ` -as of server version 4.0 which provide atomic persistence across multiple -documents. - - -Reloading -========= - -Use the ``reload`` method to fetch the most recent version of a document from -the database. Any unsaved modifications to the document's attributes are lost: - -.. code-block:: ruby - - band = Band.create!(name: 'foo') - # => # - - band.name = 'bar' - band - # => # - - band.reload - # => # - -When a document is reloaded, all of its embedded associations are also reloaded -in the same query (since embedded documents are stored in the parent document -on the server). If a document has referenced associations, the loaded -associations' are not reloaded but their values are cleared, such that these -associations would be loaded from the database at the next access. - -.. note:: - - Some operations on associations, for example assignment, persists the new - document. In these cases there may not be any unsaved modifications to - revert by reloading. In the following example, the assignment of the - empty array to the association is immediately persisted and reloading - does not make any changes to the document: - - .. code-block:: ruby - - # Assuming band has many tours, which could be referenced: - band = Band.create!(tours: [Tour.create!]) - # ... or embedded: - band = Band.create!(tours: [Tour.new]) - - # This writes the empty tour list into the database. - band.tours = [] - - # There are no unsaved modifications in band at this point to be reverted. - band.reload - - # Returns the empty array since this is what is in the database. - band.tours - # => [] - -If the model has a :ref:`shard key ` defined, the shard key value -is included in the reloading query. - -If the database does not contain a matching document, Mongoid normally raises -``Mongoid::Errors::DocumentNotFound``. However, if the configuration option -``raise_not_found_error`` is set to ``false``, and the database does not -contain a matching document, Mongoid replaces the current document with a newly -created document whose attributes are set to default values. Importantly, this -generally causes the ``_id`` of the document to change, as the following -example demonstrates: - -.. code-block:: ruby - - band = Band.create! - # => # - - Mongoid.raise_not_found_error = false - band.destroy - - band.reload - # => # - -For this reason, it is not recommended to use ``reload`` when -``raise_not_found_error`` is set to ``false``. - - -Reloading Unsaved Documents ---------------------------- - -``reload`` can be called when the document has not yet been persisted. -In this case ``reload`` performs a ``find`` query using the ``id`` value -specified in the document (and the shard key value, if a shard key is defined): - -.. code-block:: ruby - - existing = Band.create!(name: 'Photek') - - # Unsaved document - band = Band.new(id: existing.id) - band.reload - band.name - # => "Photek" - - -Accessing Field Values -====================== - -Mongoid provides several ways of accessing field values. - -.. note:: - - All of the access methods described below raise - ``Mongoid::Errors::AttributeNotLoaded`` when the field being accessed is - :ref:`projected out `, either by virtue of not being included in - :ref:`only ` or by virtue of being included in - :ref:`without `. This applies to both reads and writes. - - -Getters & Setters ------------------ - -The recommended way is to use the getter and setter methods generated for -each declared field: - -.. code-block:: ruby - - class Person - include Mongoid::Document - - field :first_name - end - - person = Person.new - - person.first_name = "Artem" - person.first_name - # => "Artem" - -To use this mechanism, each field must be explicitly declared, or the -model class must enable :ref:`dynamic fields `. - - -Custom Getters & Setters ------------------------- - -It is possible to explicitly define the getter and setter methods to provide -custom behavior when reading or writing fields, for example value -transformations or storing values under different field names. In this case -``read_attribute`` and ``write_attribute`` methods can be used to read and -write the values directly into the attributes hash: - -.. code-block:: ruby - - class Person - include Mongoid::Document - - def first_name - read_attribute(:fn) - end - - def first_name=(value) - write_attribute(:fn, value) - end - end - - person = Person.new - - person.first_name = "Artem" - person.first_name - # => "Artem" - - person.attributes - # => {"_id"=>BSON::ObjectId('606477dc2c97a628cf47075b'), "fn"=>"Artem"} - -.. note:: - - The custom setters are called during the assignment of - :ref:`nested attributes `, however they are called before - the associations are set up. Because of this, associations may not always - be available during these methods, and it is encouraged to include checks - for their presence whenever referring to them. :ref:`Callbacks ` - can also be used to perform operations on certain events, and associations - will have already been setup and are available during their execution. - -.. _read-write-attribute: - -``read_attribute`` & ``write_attribute`` ----------------------------------------- - -The ``read_attribute`` and ``write_attribute`` methods can be used explicitly -as well. Note that if a field specifies its :ref:`storage field name -`, both ``read_attribute`` and ``write_attribute`` -accept either the declared field name or the storage field name for operations: - -.. code-block:: ruby - - class Person - include Mongoid::Document - - field :first_name, as: :fn - field :last_name, as: :ln - end - - person = Person.new(first_name: "Artem") - # => # - - person.read_attribute(:first_name) - # => "Artem" - - person.read_attribute(:fn) - # => "Artem" - - person.write_attribute(:last_name, "Pushkin") - person - # => # - - person.write_attribute(:ln, "Medvedev") - person - # => # - -``read_attribute`` and ``write_attribute`` do not require that a field with -the used name is defined, but writing field values with ``write_attribute`` -does not cause the respective field to be defined either: - -.. code-block:: ruby - - person.write_attribute(:undefined, "Hello") - person - # => # - person.attributes - # => {"_id"=>BSON::ObjectId('60647b212c97a6292c195b4c'), "first_name"=>"Artem", "last_name"=>"Medvedev", "undefined"=>"Hello"} - - person.read_attribute(:undefined) - # => "Hello" - person.undefined - # raises NoMethodError - -When ``read_attribute`` is used to access a missing field, it returns ``nil``. - - -Hash Access ------------ - -Mongoid model instances define the ``[]`` and ``[]=`` methods to provide -``Hash`` style access to the attributes. ``[]`` is an alias for -``read_attribute`` and ``[]=`` is an alias for ``write_attribute``; see -the section on :ref:`read_attribute and write_attribute ` -for the detailed description of their behavior. - -.. code-block:: ruby - - class Person - include Mongoid::Document - - field :first_name, as: :fn - field :last_name, as: :ln - end - - person = Person.new(first_name: "Artem") - - person["fn"] - # => "Artem" - - person[:first_name] - # => "Artem" - - person[:ln] = "Medvedev" - person - # => # - - person["last_name"] = "Pushkin" - person - # => # - - -Bulk Attribute Writes ---------------------- - -In cases where you want to set multiple field values at once, there are a few -different ways of accomplishing this as well. - -.. code-block:: ruby - - # Get the field values as a hash. - person.attributes - - # Set the field values in the document. - Person.new(first_name: "Jean-Baptiste", middle_name: "Emmanuel") - person.attributes = { first_name: "Jean-Baptiste", middle_name: "Emmanuel" } - person.write_attributes( - first_name: "Jean-Baptiste", - middle_name: "Emmanuel", - ) - - -Dirty Tracking -============== - -Mongoid supports tracking of changed or "dirty" fields with an API that mirrors that of -Active Model. If a defined field has been modified in a model the model will be marked as -dirty and some additional behavior comes into play. - - -Viewing Changes ---------------- - -There are various ways to view what has been altered on a model. Changes are recorded -from the time a document is instantiated, either as a new document or via loading from -the database up to the time it is saved. Any persistence operation clears the changes. - -.. code-block:: ruby - - class Person - include Mongoid::Document - field :name, type: String - end - - person = Person.first - person.name = "Alan Garner" - - # Check to see if the document has changed. - person.changed? # true - - # Get an array of the names of the changed fields. - person.changed # [ :name ] - - # Get a hash of the old and changed values for each field. - person.changes # { "name" => [ "Alan Parsons", "Alan Garner" ] } - - # Check if a specific field has changed. - person.name_changed? # true - - # Get the changes for a specific field. - person.name_change # [ "Alan Parsons", "Alan Garner" ] - - # Get the previous value for a field. - person.name_was # "Alan Parsons" - -.. note:: - - Setting the associations on a document does not cause the ``changes`` or - ``changed_attributes`` hashes to be modified. This is true for all associations - whether referenced or embedded. Note that changing the _id(s) field on - referenced associations does cause the changes to show up in the ``changes`` - and the ``changed_attributes`` hashes. - - -Resetting Changes ------------------ - -You can reset changes of a field to its previous value by calling the reset method. - -.. code-block:: ruby - - person = Person.first - person.name = "Alan Garner" - - # Reset the changed name back to the original - person.reset_name! - person.name # "Alan Parsons" - - -Persistence ------------ - -Mongoid uses dirty tracking as the core of its persistence operations. It looks at the -changes on a document and atomically updates only what has changed, unlike other frameworks -that write the entire document on each save. If no changes have been made, Mongoid will -not hit the database on a call to ``Model#save``. - - -Viewing Previous Changes ------------------------- - -After a document has been persisted, you can see what the changes were previously by -calling ``Model#previous_changes``. - -.. code-block:: ruby - - person = Person.first - person.name = "Alan Garner" - person.save # Clears out current changes. - - # View the previous changes. - person.previous_changes # { "name" => [ "Alan Parsons", "Alan Garner" ] } - - -Updating Container Fields -========================= - -Be aware that, until -`MONGOID-2951 `_ -is resolved, all fields including container ones must be assigned to for -their values to be persisted to the database. - -For example, adding to a set like this does not work: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :tours, type: Set - end - - band = Band.new - band.tours - # => # - - band.tours << 'London' - # => # - band.tours - # => # - -Instead, the field value must be modified outside of the model and assigned -back to the model as follows: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :tours, type: Set - end - - band = Band.new - - tours = band.tours - # => # - - tours << 'London' - # => # - - band.tours = tours - # => # - - band.tours - # => # - - -.. _readonly-documents: - -Readonly Documents -================== - -Documents can be marked read-only in two ways, depending on the value of the -``Mongoid.legacy_readonly`` feature flag: - -If this flag is turned off, a document is marked read-only when the ``#readonly!`` -method is called on that documnet. A read-only document, with this flag turned off, -will raise a ReadonlyDocument error on attempting to perform any persistence -operation, including (but not limited to) saving, updating, deleting and -destroying. Note that reloading does not reset the read-only state. - -.. code:: ruby - - band = Band.first - band.readonly? # => false - band.readonly! - band.readonly? # => true - band.name = "The Rolling Stones" - band.save # => raises ReadonlyDocument error - band.reload.readonly? # => true - -If this flag is turned on, a document is marked read-only when that document -has been projected (i.e. using ``#only`` or ``#without``). A read-only document, -with this flag turned on, will not be deletable or destroyable (a -``ReadonlyDocument`` error will be raised), but will be saveable and updatable. -The read-only status is reset on reloading the document. - -.. code:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :genre, type: String - end - - band = Band.only(:name).first - band.readonly? # => true - band.destroy # => raises ReadonlyDocument error - band.reload.readonly? # => false - - -Overriding ``readonly?`` ------------------------- - -Another way to make a document read-only is by overriding the readonly? method: - -.. code:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :genre, type: String - - def readonly? - true - end - end - - band = Band.first - band.readonly? # => true - band.destroy # => raises ReadonlyDocument error diff --git a/docs/reference/fields.txt b/docs/reference/fields.txt deleted file mode 100644 index 5e29bfeec4..0000000000 --- a/docs/reference/fields.txt +++ /dev/null @@ -1,1778 +0,0 @@ -.. _fields: - -**************** -Field Definition -**************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -.. _field-types: - -Field Types -=========== - -MongoDB stores underlying document data using -`BSON types `_, and -Mongoid converts BSON types to Ruby types at runtime in your application. -For example, a field defined with ``type: :float`` will use the Ruby ``Float`` -class in-memory and will persist in the database as the the BSON ``double`` type. - -Field type definitions determine how Mongoid behaves when constructing queries -and retrieving/writing fields from/to the database. Specifically: - -1. When assigning values to fields at runtime, the values are converted to the - specified type. -2. When persisting data to MongoDB, the data is sent in an appropriate - type, permitting richer data manipulation within MongoDB or by other - tools. -3. When querying documents, query parameters are converted to the specified - type before being sent to MongoDB. -4. When retrieving documents from the database, field values are converted - to the specified type. - -Changing the field definitions in a model class does not alter data already stored in -MongoDB. To update type or contents of fields of existing documents, -the field must be re-saved to the database. Note that, due to Mongoid -tracking which attributes on a model change and only saving the changed ones, -it may be necessary to explicitly write a field value when changing the -type of an existing field without changing the stored values. - -Consider a simple class for modeling a person in an application. A person may -have a name, date_of_birth, and weight. We can define these attributes -on a person by using the ``field`` macro. - -.. code-block:: ruby - - class Person - include Mongoid::Document - field :name, type: String - field :date_of_birth, type: Date - field :weight, type: Float - end - -The valid types for fields are as follows: - -- ``Array`` -- ``BSON::Binary`` -- :ref:`BigDecimal ` -- ``Mongoid::Boolean``, which may be specified simply as ``Boolean`` in the - scope of a class which included ``Mongoid::Document``. -- :ref:`Date ` -- :ref:`DateTime ` -- ``Float`` -- :ref:`Hash ` -- ``Integer`` -- :ref:`Object ` -- ``BSON::ObjectId`` -- ``Range`` -- :ref:`Regexp ` -- ``Set`` -- ``String`` -- :ref:`Mongoid::StringifiedSymbol `, - which may be specified simply as ``StringifiedSymbol`` in the scope of a - class which included ``Mongoid::Document``. -- :ref:`Symbol ` -- :ref:`Time ` -- ``ActiveSupport::TimeWithZone`` - -Mongoid also recognizes the string ``"Boolean"`` as an alias for the -``Mongoid::Boolean`` class. - -To define custom field types, refer to :ref:`Custom Field Types ` below. - -.. note:: - - Using the ``BSON::Int64`` and ``BSON::Int32`` types as field types is unsupported. - Saving these types to the database will work as expected, however, querying them - will return the native Ruby ``Integer`` type. Querying fields of type - ``BSON::Decimal128`` will return values of type ``BSON::Decimal128`` in - BSON <=4 and values of type ``BigDecimal`` in BSON 5+. - - -.. _untyped-fields: - -Untyped Fields --------------- - -Not specifying a type for a field is the same as specifying the ``Object`` -type. Such fields are untyped: - -.. code-block:: ruby - - class Product - include Mongoid::Document - - field :properties - # Equivalent to: - field :properties, type: Object - end - -An untyped field can store values of any type which is directly serializable -to BSON. This is useful when a field may contain values of different types -(i.e. it is a variant type field), or when the type of values is not known -ahead of time: - -.. code-block:: ruby - - product = Product.new(properties: "color=white,size=large") - product.properties - # => "color=white,size=large" - - product = Product.new(properties: {color: "white", size: "large"}) - product.properties - # => {:color=>"white", :size=>"large"} - -When values are assigned to the field, Mongoid still performs mongoization but -uses the class of the value rather than the field type for mongoization logic. - -.. code-block:: ruby - - product = Product.new(properties: 0..10) - product.properties - # The range 0..10, mongoized: - # => {"min"=>0, "max"=>10} - -When reading data from the database, Mongoid does not perform any type -conversions on untyped fields. For this reason, even though it is possible -to write any BSON-serializable value into an untyped fields, values which -require special handling on the database reading side will generally not work -correctly in an untyped field. Among field types supported by Mongoid, -values of the following types should not be stored in untyped fields: - -- ``Date`` (values will be returned as ``Time``) -- ``DateTime`` (values will be returned as ``Time``) -- ``Range`` (values will be returned as ``Hash``) - - -.. _field-type-stringified-symbol: - -Field Type: StringifiedSymbol ------------------------------ - -The ``StringifiedSymbol`` field type is the recommended field type for storing -values that should be exposed as symbols to Ruby applications. When using the ``Symbol`` field type, -Mongoid defaults to storing values as BSON symbols. For more information on the -BSON symbol type, see :ref:`here `. -However, the BSON symbol type is deprecated and is difficult to work with in programming languages -without native symbol types, so the ``StringifiedSymbol`` type allows the use of symbols -while ensuring interoperability with other drivers. The ``StringifiedSymbol`` type stores all data -on the database as strings, while exposing values to the application as symbols. - -An example usage is shown below: - -.. code-block:: ruby - - class Post - include Mongoid::Document - - field :status, type: StringifiedSymbol - end - - post = Post.new(status: :hello) - # status is stored as "hello" on the database, but returned as a Symbol - post.status - # => :hello - - # String values can be assigned also: - post = Post.new(status: "hello") - # status is stored as "hello" on the database, but returned as a Symbol - post.status - # => :hello - -All non-string values will be stringified upon being sent to the database (via ``to_s``), and -all values will be converted to symbols when returned to the application. Values that cannot be -converted directly to symbols, such as integers and arrays, will first be converted to strings and -then symbols before being returned to the application. - -For example, setting an integer as ``status``: - -.. code-block:: ruby - - post = Post.new(status: 42) - post.status - # => :"42" - -If the ``StringifiedSymbol`` type is applied to a field that contains BSON symbols, the values -will be stored as strings instead of BSON symbols on the next save. This permits transparent lazy -migration from fields that currently store either strings or BSON symbols in the database to the -``StringifiedSymbol`` field type. - - -.. _field-type-symbol: - -Field Type: Symbol ------------------- - -New applications should use the :ref:`StringifiedSymbol field type ` -to store Ruby symbols in the database. The ``StringifiedSymbol`` field type -provides maximum compatibility with other applications and programming languages -and has the same behavior in all circumstances. - -Mongoid also provides the deprecated ``Symbol`` field type for serializing -Ruby symbols to BSON symbols. Because the BSON specification deprecated the -BSON symbol type, the ``bson`` gem will serialize Ruby symbols into BSON strings -when used on its own. However, in order to maintain backwards compatibility -with older datasets, the ``mongo`` gem overrides this behavior to serialize Ruby -symbols as BSON symbols. This is necessary to be able to specify queries for -documents which contain BSON symbols as fields. - -To override the default behavior and configure the ``mongo`` gem (and thereby -Mongoid as well) to encode symbol values as strings, include the following code -snippet in your project: - -.. code-block:: ruby - - class Symbol - def bson_type - BSON::String::BSON_TYPE - end - end - - -.. _field-type-hash: - -Field Type: Hash ----------------- - -When using a field of type Hash, be wary of adhering to the -`legal key names for mongoDB `_, -or else the values will not store properly. - -.. code-block:: ruby - - class Person - include Mongoid::Document - field :first_name - field :url, type: Hash - - # will update the fields properly and save the values - def set_vals - self.first_name = 'Daniel' - self.url = {'home_page' => 'http://www.homepage.com'} - save - end - - # all data will fail to save due to the illegal hash key - def set_vals_fail - self.first_name = 'Daniel' - self.url = {'home.page' => 'http://www.homepage.com'} - save - end - end - - -.. _field-type-time: - -Field Type: Time ----------------- - -``Time`` fields store values as ``Time`` instances in the :ref:`configured -time zone `. - -``Date`` and ``DateTime`` instances are converted to ``Time`` instances upon -assignment to a ``Time`` field: - -.. code-block:: ruby - - class Voter - include Mongoid::Document - - field :registered_at, type: Time - end - - Voter.new(registered_at: Date.today) - # => # - -In the above example, the value was interpreted as the beginning of today in -local time, because the application was not configured to use UTC times. - -.. note:: - - When the database contains a string value for a ``Time`` field, Mongoid - parses the string value using ``Time.parse`` which considers values without - time zones to be in local time. - - -.. _field-type-date: - -Field Type: Date ----------------- - -Mongoid allows assignment of values of several types to ``Date`` fields: - -- ``Date`` - the provided date is stored as is. -- ``Time``, ``DateTime``, ``ActiveSupport::TimeWithZone`` - the date component - of the value is taken in the value's time zone. -- ``String`` - the date specified in the string is used. -- ``Integer``, ``Float`` - the value is taken to be a UTC timestamp which is - converted to the :ref:`configured time zone ` (note that - ``Mongoid.use_utc`` has no effect on this conversion), then the date is - taken from the resulting time. - -In other words, if a date is specified in the value, that date is used without -first converting the value to the configured time zone. - -As a date & time to date conversion is lossy (it discards the time component), -especially if an application operates with times in different time zones it is -recommended to explicitly convert ``String``, ``Time`` and ``DateTime`` -objects to ``Date`` objects before assigning the values to fields of type -``Date``. - -.. note:: - - When the database contains a string value for a ``Date`` field, Mongoid - parses the string value using ``Time.parse``, discards the time portion of - the resulting ``Time`` object and uses the date portion. ``Time.parse`` - considers values without time zones to be in local time. - - -.. _field-type-date-time: - -Field Type: DateTime ---------------------- - -MongoDB stores all times as UTC timestamps. When assigning a value to a -``DateTime`` field, or when querying a ``DateTime`` field, Mongoid -converts the passed in value to a UTC ``Time`` before sending it to the -MongoDB server. - -``Time``, ``ActiveSupport::TimeWithZone`` and ``DateTime`` objects embed -time zone information, and the value persisted is the specified moment in -time, in UTC. When the value is retrieved, the time zone in which it is -returned is defined by the :ref:`configured time zone settings `. - -.. code-block:: ruby - - class Ticket - include Mongoid::Document - field :opened_at, type: DateTime - end - - Time.zone = 'Berlin' - - ticket = Ticket.create!(opened_at: '2018-02-18 07:00:08 -0500') - - ticket.opened_at - # => Sun, 18 Feb 2018 13:00:08 +0100 - ticket - # => # - - Time.zone = 'America/New_York' - ticket.opened_at - # => Sun, 18 Feb 2018 07:00:08 -0500 - - Mongoid.use_utc = true - ticket.opened_at - # => Sun, 18 Feb 2018 12:00:08 +0000 - -Mongoid also supports casting integers and floats to ``DateTime``. When -doing so, the integers/floats are assumed to be Unix timestamps (in UTC): - -.. code-block:: ruby - - ticket.opened_at = 1544803974 - ticket.opened_at - # => Fri, 14 Dec 2018 16:12:54 +0000 - -If a string is used as a ``DateTime`` field value, the behavior depends on -whether the string includes a time zone. If no time zone is specified, -the :ref:`default Mongoid time zone ` is used: - -.. code-block:: ruby - - Time.zone = 'America/New_York' - ticket.opened_at = 'Mar 4, 2018 10:00:00' - ticket.opened_at - # => Sun, 04 Mar 2018 15:00:00 +0000 - -If a time zone is specified, it is respected: - -.. code-block:: ruby - - ticket.opened_at = 'Mar 4, 2018 10:00:00 +01:00' - ticket.opened_at - # => Sun, 04 Mar 2018 09:00:00 +0000 - -.. note:: - - When the database contains a string value for a ``DateTime`` field, Mongoid - parses the string value using ``Time.parse`` which considers values without - time zones to be in local time. - - -.. _field-type-regexp: - -Field Type: Regexp ------------------- - -MongoDB supports storing regular expressions in documents, and querying using -regular expressions. Note that MongoDB uses -`Perl-compatible regular expressions (PCRE) `_ -and Ruby uses `Onigmo `_, which is a -fork of `Oniguruma regular expression engine `_. -The two regular expression implementations generally provide equivalent -functionality but have several important syntax differences. - -When a field is declared to be of type Regexp, Mongoid converts Ruby regular -expressions to BSON regular expressions and stores the result in MongoDB. -Retrieving the field from the database produces a ``BSON::Regexp::Raw`` -instance: - -.. code-block:: ruby - - class Token - include Mongoid::Document - - field :pattern, type: Regexp - end - - token = Token.create!(pattern: /hello.world/m) - token.pattern - # => /hello.world/m - - token.reload - token.pattern - # => # - -Use ``#compile`` method on ``BSON::Regexp::Raw`` to get back the Ruby regular -expression: - -.. code-block:: ruby - - token.pattern.compile - # => /hello.world/m - -Note that, if the regular expression was not originally a Ruby one, calling -``#compile`` on it may produce a different regular expression. For example, -the following is a PCRE matching a string that ends in "hello": - -.. code-block:: ruby - - BSON::Regexp::Raw.new('hello$', 's') - # => # - -Compiling this regular expression produces a Ruby regular expression that -matches strings containing "hello" before a newline, besides strings ending in -"hello": - -.. code-block:: ruby - - BSON::Regexp::Raw.new('hello$', 's').compile =~ "hello\nworld" - # => 0 - -This is because the meaning of ``$`` is different between PCRE and Ruby -regular expressions. - -.. _field-type-big-decimal: - -BigDecimal Fields ------------------ - -The ``BigDecimal`` field type is used to store numbers with increased precision. - -The ``BigDecimal`` field type stores its values in two different ways in the -database, depending on the value of the ``Mongoid.map_big_decimal_to_decimal128`` -global config option. If this flag is set to false (which is the default), -the ``BigDecimal`` field will be stored as a string, otherwise it will be stored -as a ``BSON::Decimal128``. - -The ``BigDecimal`` field type has some limitations when converting to and from -a ``BSON::Decimal128``: - -- ``BSON::Decimal128`` has a limited range and precision, while ``BigDecimal`` - has no restrictions in terms of range and precision. ``BSON::Decimal128`` has - a max value of approximately ``10^6145`` and a min value of approximately - ``-10^6145``, and has a maximum of 34 bits of precision. When attempting to - store values that don't fit into a ``BSON::Decimal128``, it is recommended to - have them stored as a string instead of a ``BSON::Decimal128``. You can do - that by setting ``Mongoid.map_big_decimal_to_decimal128`` to ``false``. If a - value that does not fit in a ``BSON::Decimal128`` is attempted to be stored - as one, an error will be raised. - -- ``BSON::Decimal128`` is able to accept signed ``NaN`` values, while - ``BigDecimal`` is not. When retrieving signed ``NaN`` values from - the database using the ``BigDecimal`` field type, the ``NaN`` will be - unsigned. - -- ``BSON::Decimal128`` maintains trailing zeroes when stored in the database. - ``BigDecimal``, however, does not maintain trailing zeroes, and therefore - retrieving ``BSON::Decimal128`` values using the ``BigDecimal`` field type - may result in a loss of precision. - -There is an additional caveat when storing a ``BigDecimal`` in a field with no -type (i.e. a dynamically typed field) and ``Mongoid.map_big_decimal_to_decimal128`` -is ``false``. In this case, the ``BigDecimal`` is stored as a string, and since a -dynamic field is being used, querying for that field with a ``BigDecimal`` will -not find the string for that ``BigDecimal``, since the query is looking for a -``BigDecimal``. In order to query for that string, the ``BigDecimal`` must -first be converted to a string with ``to_s``. Note that this is not a problem -when the field has type ``BigDecimal``. - -If you wish to avoid using ``BigDecimal`` altogether, you can set the field -type to ``BSON::Decimal128``. This will allow you to keep track of trailing -zeroes and signed ``NaN`` values. - -Migration to ``decimal128``-backed ``BigDecimal`` Field -``````````````````````````````````````````````````````` -In a future major version of Mongoid, the ``Mongoid.map_big_decimal_to_decimal128`` -global config option will be defaulted to ``true``. When this flag is turned on, -``BigDecimal`` values in queries will not match to the strings that are already -stored in the database; they will only match to ``decimal128`` values that are -in the database. If you have a ``BigDecimal`` field that is backed by strings, -you have three options: - -1. The ``Mongoid.map_big_decimal_to_decimal128`` global config option can be - set to ``false``, and you can continue storing your ``BigDecimal`` values as - strings. Note that you are surrendering the advantages of storing ``BigDecimal`` - values as a ``decimal128``, like being able to do queries and aggregations - based on the numerical value of the field. - -2. The ``Mongoid.map_big_decimal_to_decimal128`` global config option can be - set to ``true``, and you can convert all values for that field from strings to - ``decimal128`` values in the database. You should do this conversion before - setting the global config option to true. An example query to accomplish this - is as follows: - - .. code-block:: javascript - - db.bands.updateMany({ - "field": { "$exists": true } - }, [ - { - "$set": { - "field": { "$toDecimal": "$field" } - } - } - ]) - - This query updates all documents that have the given field, setting that - field to its corresponding ``decimal128`` value. Note that this query only - works in MongoDB 4.2+. - -3. The ``Mongoid.map_big_decimal_to_decimal128`` global config option can be - set to ``true``, and you can have both strings and ``decimal128`` values for - that field. This way, only ``decimal128`` values will be inserted into and - updated to the database going forward. Note that you still don't get the - full advantages of using only ``decimal128`` values, but your dataset is - slowly migrating to all ``decimal128`` values, as old string values are - updated to ``decimal128`` and new ``decimal128`` values are added. With this - setup, you can still query for ``BigDecimal`` values as follows: - - .. code-block:: ruby - - Mongoid.map_big_decimal_to_decimal128 = true - big_decimal = BigDecimal('2E9') - Band.in(sales: [big_decimal, big_decimal.to_s]).to_a - - This query will find all values that are either a ``decimal128`` value or - a string that match that value. - - -Using Symbols Or Strings Instead Of Classes -------------------------------------------- - -Mongoid permits using symbols or strings instead of classes to specify the -type of fields, for example: - -.. code-block:: ruby - - class Order - include Mongoid::Document - - field :state, type: :integer - # Equivalent to: - field :state, type: "integer" - # Equivalent to: - field :state, type: Integer - end - -Only standard field types as listed below can be specified using symbols or -strings in this manner. Mongoid recognizes the following expansions: - -- ``:array`` => ``Array`` -- ``:big_decimal`` => ``BigDecimal`` -- ``:binary`` => ``BSON::Binary`` -- ``:boolean`` => ``Mongoid::Boolean`` -- ``:date`` => ``Date`` -- ``:date_time`` => ``DateTime`` -- ``:float`` => ``Float`` -- ``:hash`` => ``Hash`` -- ``:integer`` => ``Integer`` -- ``:object_id`` => ``BSON::ObjectId`` -- ``:range`` => ``Range`` -- ``:regexp`` => ``Regexp`` -- ``:set`` => ``Set`` -- ``:string`` => ``String`` -- ``:stringified_symbol`` => ``StringifiedSymbol`` -- ``:symbol`` => ``Symbol`` -- ``:time`` => ``Time`` - - -.. _field-default-values: - -Specifying Field Default Values -------------------------------- - -A field can be configured to have a default value. The default value can be -fixed, as in the following example: - -.. code-block:: ruby - - class Order - include Mongoid::Document - - field :state, type: String, default: 'created' - end - -The default value can also be specified as a ``Proc``: - -.. code-block:: ruby - - class Order - include Mongoid::Document - - field :fulfill_by, type: Time, default: ->{ Time.now + 3.days } - end - -.. note:: - - Default values that are not ``Proc`` instances are evaluated at class load - time, meaning the following two definitions are not equivalent: - - .. code-block:: ruby - - field :submitted_at, type: Time, default: Time.now - field :submitted_at, type: Time, default: ->{ Time.now } - - The second definition is most likely the desired one, which causes the - time of submission to be set to the current time at the moment of - document instantiation. - -To set a default which depends on the document's state, use ``self`` -inside the ``Proc`` instance which would evaluate to the document instance -being operated on: - -.. code-block:: ruby - - field :fulfill_by, type: Time, default: ->{ - # Order should be fulfilled in 2 business hours. - if (7..8).include?(self.submitted_at.hour) - self.submitted_at + 4.hours - elsif (9..3).include?(self.submitted_at.hour) - self.submitted_at + 2.hours - else - (self.submitted_at + 1.day).change(hour: 11) - end - } - -When defining a default value as a ``Proc``, Mongoid will apply the default -after all other attributes are set and associations are initialized. -To have the default be applied before the other attributes are set, -use the ``pre_processed: true`` field option: - -.. code-block:: ruby - - field :fulfill_by, type: Time, default: ->{ Time.now + 3.days }, - pre_processed: true - -The ``pre_processed: true`` option is also necessary when specifying a custom -default value via a ``Proc`` for the ``_id`` field, to ensure the ``_id`` -is set correctly via associations: - -.. code-block:: ruby - - field :_id, type: String, default: -> { 'hello' }, pre_processed: true - - -.. _storage-field-names: - -Specifying Storage Field Names ------------------------------- - -One of the drawbacks of having a schemaless database is that MongoDB must -store all field information along with every document, meaning that it -takes up a lot of storage space in RAM and on disk. A common pattern to limit -this is to alias fields to a small number of characters, while keeping the -domain in the application expressive. Mongoid allows you to do this and -reference the fields in the domain via their long names in getters, setters, -and criteria while performing the conversion for you. - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :n, as: :name, type: String - end - - band = Band.new(name: "Placebo") - band.attributes # { "n" => "Placebo" } - - criteria = Band.where(name: "Placebo") - criteria.selector # { "n" => "Placebo" } - - -.. _field-aliases: - -Field Aliases -------------- - -It is possible to define field aliases. The value will be stored in the -destination field but can be accessed from either the destination field or -from the aliased field: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :name, type: String - alias_attribute :n, :name - end - - band = Band.new(n: 'Astral Projection') - # => # - - band.attributes - # => {"_id"=>BSON::ObjectId('5fc1c1ee2c97a64accbeb5e1'), "name"=>"Astral Projection"} - - band.n - # => "Astral Projection" - -Aliases can be removed from model classes using the ``unalias_attribute`` -method. - -.. code-block:: ruby - - class Band - unalias_attribute :n - end - -.. _unalias-id: - -Unaliasing ``id`` -````````````````` - -``unalias_attribute`` can be used to remove the predefined ``id`` alias. -This is useful for storing different values in ``id`` and ``_id`` fields: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - unalias_attribute :id - field :id, type: String - end - - Band.new(id: '42') - # => # - - -Reserved Names --------------- - -Attempting to define a field on a document that conflicts with a reserved -method name in Mongoid will raise an error. The list of reserved names can -be obtained by invoking the ``Mongoid.destructive_fields`` method. - - -Field Redefinition ------------------- - -By default Mongoid allows redefining fields on a model. To raise an error -when a field is redefined, set the ``duplicate_fields_exception`` -:ref:`configuration option ` to ``true``. - -With the option set to true, the following example will raise an error: - -.. code-block:: ruby - - class Person - include Mongoid::Document - - field :name - - field :name, type: String - end - -To define the field anyway, use the ``overwrite: true`` option: - -.. code-block:: ruby - - class Person - include Mongoid::Document - - field :name - - field :name, type: String, overwrite: true - end - - -.. _custom-id: - -Custom IDs ----------- - -By default, Mongoid defines the ``_id`` field on documents to contain a -``BSON::ObjectId`` value which is automatically generated by Mongoid. - -It is possible to replace the ``_id`` field definition to change the type -of the ``_id`` values or have different default values: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :_id, type: String, default: ->{ name } - end - -It is possible to omit the default entirely: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :_id, type: String - end - -If the default on ``_id`` is omitted, and no ``_id`` value is provided by -your application, Mongoid will persist the document without the ``_id`` -value. In this case, if the document is a top-level document, an ``_id`` -value will be assigned by the server; if the document is an embedded document, -no ``_id`` value will be assigned. Mongoid will not automatically retrieve -this value, if assigned, when the document is persisted - you -must obtain the persisted value (and the complete persisted document) using -other means: - -.. code-block:: ruby - - band = Band.create! - => # - band.id - => nil - band.reload - # raises Mongoid::Errors::DocumentNotFound - Band.last - => # - -Omitting ``_id`` fields is more common in :ref:`embedded documents `. - -Mongoid also defines the ``id`` field aliased to ``_id``. The ``id`` -alias can :ref:`be removed ` if desired (such as to integrate -with systems that use the ``id`` field to store value different from ``_id``. - -.. _uncastable-values: - -Uncastable Values ------------------ - -In Mongoid 8, Mongoid has standardized the treatment of the assignment and -reading of "uncastable" values. A value is considered "uncastable" when it -cannot be coerced to the type of its field. For example, an array would be an -"uncastable" value to an Integer field. - - -Assigning Uncastable Values -``````````````````````````` - -The assignment of uncastable values has been standardized to assign ``nil`` by -default. Consider the following example: - -.. code:: - - class User - include Mongoid::Document - - field :name, type: Integer - end - - User.new(name: [ "hello" ]) - -Assigning an array to a field of type Integer doesn't work since an array can't -be coerced to an Integer. The assignment of uncastable values to a field will -cause a ``nil`` to be written: - -.. code:: - - user = User.new(name: [ "Mike", "Trout" ]) - # => # - -Note that the original uncastable values will be stored in the -``attributes_before_type_cast`` hash with their field names: - -.. code:: - - user.attributes_before_type_cast["name"] - # => ["Mike", "Trout"] - -.. note:: - - Note that for numeric fields, any class that defines ``to_i`` for Integer - fields, ``to_f`` for Floats, and ``to_d`` for BigDecimals, is castable. - Strings are the exception and will only call the corresponding ``to_*`` - method if the string is numeric. If a class only defines ``to_i`` and not - ``to_f`` and is being assigned to a Float field, this is uncastable, and Mongoid - will not perform a two-step conversion (i.e. ``to_i`` and then ``to_f``). - - -Reading Uncastable Values -````````````````````````` - -When documents in the database contain values of different types than their -representations in Mongoid, if Mongoid cannot coerce them into the correct type, -it will replace the value with ``nil``. Consider the following model and document in the -database: - -.. code:: - - class User - include Mongoid::Document - - field :name, type: Integer - end - -.. code:: - - { _id: ..., name: [ "Mike", "Trout" ] } - -Reading this document from the database will result in the model's name field -containing ``nil``: - -.. code:: - - User.first.name - # => nil - -The database value of type array cannot be stored in the attribute, since the -array can't be coerced to an Integer. Note that the original uncastable values -will be stored in the ``attributes_before_type_cast`` hash with their field -names: - -.. code:: - - user.attributes_before_type_cast["name"] - # => ["Mike", "Trout"] - -.. note:: - - The ``demongoize`` methods on container objects (i.e. Hash, Array) have not - been changed to permit automatic persistence of mutated container attributes. - See `MONGOID-2951 `_ for a - longer discussion of this topic. - - -.. _customizing-field-behavior: - -Customizing Field Behavior -========================== - -Mongoid offers several ways to customize the behavior of fields. - - -.. _custom-getters-and-setters: - -Custom Getters And Setters --------------------------- - -You may override getters and setters for fields to modify the values -when they are being accessed or written. The getters and setters use the -same name as the field. Use ``read_attribute`` and ``write_attribute`` -methods inside the getters and setters to operate on the raw attribute -values. - -For example, Mongoid provides the ``:default`` field option to write a -default value into the field. If you wish to have a field default value -in your application but do not wish to persist it, you can override the -getter as follows: - -.. code-block:: ruby - - class DistanceMeasurement - include Mongoid::Document - - field :value, type: Float - field :unit, type: String - - def unit - read_attribute(:unit) || "m" - end - - def to_s - "#{value} #{unit}" - end - end - - measurement = DistanceMeasurement.new(value: 2) - measurement.to_s - # => "2.0 m" - measurement.attributes - # => {"_id"=>BSON::ObjectId('613fa0b0a15d5d61502f3447'), "value"=>2.0} - -To give another example, a field which converts empty strings to nil values -may be implemented as follows: - -.. code-block:: ruby - - class DistanceMeasurement - include Mongoid::Document - - field :value, type: Float - field :unit, type: String - - def unit=(value) - if value.blank? - value = nil - end - write_attribute(:unit, value) - end - end - - measurement = DistanceMeasurement.new(value: 2, unit: "") - measurement.attributes - # => {"_id"=>BSON::ObjectId('613fa15aa15d5d617216104c'), "value"=>2.0, "unit"=>nil} - - -.. _custom-field-types: - -Custom Field Types ------------------- - -You can define custom types in Mongoid and determine how they are serialized -and deserialized. In this example, we define a new field type ``Point``, which we -can use in our model class as follows: - -.. code-block:: ruby - - class Profile - include Mongoid::Document - field :location, type: Point - end - -Then make a Ruby class to represent the type. This class must define methods -used for MongoDB serialization and deserialization as follows: - -.. code-block:: ruby - - class Point - - attr_reader :x, :y - - def initialize(x, y) - @x, @y = x, y - end - - # Converts an object of this instance into a database friendly value. - # In this example, we store the values in the database as array. - def mongoize - [ x, y ] - end - - class << self - - # Takes any possible object and converts it to how it would be - # stored in the database. - def mongoize(object) - case object - when Point then object.mongoize - when Hash then Point.new(object[:x], object[:y]).mongoize - else object - end - end - - # Get the object as it was stored in the database, and instantiate - # this custom class from it. - def demongoize(object) - Point.new(object[0], object[1]) - end - - # Converts the object that was supplied to a criteria and converts it - # into a query-friendly form. - def evolve(object) - case object - when Point then object.mongoize - else object - end - end - end - end - -The instance method ``mongoize`` takes an instance of your custom type object, and -converts it into a representation of how it will be stored in the database, i.e. to pass -to the MongoDB Ruby driver. In our example above, we want to store our ``Point`` -object as an ``Array`` in the form ``[ x, y ]``. - -The class method ``mongoize`` is similar to the instance method, however it must handle -objects of all possible types as inputs. The ``mongoize`` method is used when calling the -setter methods for fields of your custom type. - -.. code-block:: ruby - - point = Point.new(12, 24) - venue = Venue.new(location: point) # This uses the Point#mongoize instance method. - venue = Venue.new(location: [ 12, 24 ]) # This uses the Point.mongoize class method. - -The class method ``demongoize`` does the inverse of ``mongoize``. It takes the raw object -from the MongoDB Ruby driver and converts it to an instance of your custom type. -In this case, the database driver returns an ``Array`` and we instantiate a ``Point`` from it. -The ``demongoize`` method is used when calling the getters of fields for your custom type. -Note that in the example above, since ``demongoize`` calls ``Point.new``, a new instance of -``Point`` will be generated on each call to the getter. - -Mongoid will always call the ``demongoize`` method on values that were -retrieved from the database, but applications may, in theory, call -``demongoize`` with arbitrary input. It is recommended that applications add -handling for arbitrary input in their ``demongoize`` methods. We can rewrite -``Point``'s demongoize method as follows: - -.. code:: ruby - - def demongoize(object) - if object.is_a?(Array) && object.length == 2 - Point.new(object[0], object[1]) - end - end - -Notice that ``demongoize`` will only create a new ``Point`` if given an array -of length 2, and will return ``nil`` otherwise. Both the ``mongoize`` and -``demongoize`` methods should be prepared to receive arbitrary input and should -return ``nil`` on values that are uncastable to your custom type. See the -section on :ref:`Uncastable Values ` for more details. - -Lastly, the class method ``evolve`` is similar to ``mongoize``, however it is used -when transforming objects for use in Mongoid query criteria. - -.. code-block:: ruby - - point = Point.new(12, 24) - Venue.where(location: point) # This uses Point.evolve - -The ``evolve`` method should also be prepared to receive arbitrary input, -however, unlike the ``mongoize`` and ``demongoize`` methods, it should return -the inputted value on values that are uncastable to your custom type. See the -section on :ref:`Uncastable Values ` for more details. - - -.. _phantom-custom-field-types: - -Phantom Custom Field Types -`````````````````````````` - -The custom field type may perform conversions from user-visible attribute -values to the values stored in the database when the user-visible attribute -value type is different from the declared field type. For example, this -can be used to implement a mapping from one enumeration to another, to -have more descriptive values in the application and more compact values stored -in the database: - -.. code-block:: ruby - - class ColorMapping - - MAPPING = { - 'black' => 0, - 'white' => 1, - }.freeze - - INVERSE_MAPPING = MAPPING.invert.freeze - - class << self - - # Takes application-scope value and converts it to how it would be - # stored in the database. Converts invalid values to nil. - def mongoize(object) - MAPPING[object] - end - - # Get the value as it was stored in the database, and convert to - # application-scope value. Converts invalid values to nil. - def demongoize(object) - INVERSE_MAPPING[object] - end - - # Converts the object that was supplied to a criteria and converts it - # into a query-friendly form. Returns invalid values as is. - def evolve(object) - MAPPING.fetch(object, object) - end - end - end - - class Profile - include Mongoid::Document - field :color, type: ColorMapping - end - - profile = Profile.new(color: 'white') - profile.color - # => "white" - - # Writes 0 to color field - profile.save! - - -.. _custom-field-options: - -Custom Field Options --------------------- - -You may define custom options for the ``field`` macro function -which extend its behavior at the your time model classes are loaded. - -As an example, we will define a ``:max_length`` option which will add a length -validator for the field. First, declare the new field option in an initializer, -specifying its handler function as a block: - -.. code-block:: ruby - - # in /config/initializers/mongoid_custom_fields.rb - - Mongoid::Fields.option :max_length do |model, field, value| - model.validates_length_of field.name, maximum: value - end - -Then, use it your model class: - -.. code-block:: ruby - - class Person - include Mongoid::Document - - field :name, type: String, max_length: 10 - end - -Note that the handler function will be invoked whenever the option is used -in the field definition, even if the option's value is false or nil. - - -.. _dynamic-fields: - -Dynamic Fields -============== - -By default, Mongoid requires all fields that may be set on a document to -be explicitly defined using ``field`` declarations. Mongoid also supports -creating fields on the fly from an arbitrary hash or documents stored in -the database. When a model uses fields not explicitly defined, such fields -are called *dynamic fields*. - -To enable dynamic fields, include ``Mongoid::Attributes::Dynamic`` module -in the model: - -.. code-block:: ruby - - class Person - include Mongoid::Document - include Mongoid::Attributes::Dynamic - end - - bob = Person.new(name: 'Bob', age: 42) - bob.name - # => "Bob" - -It is possible to use ``field`` declarations and dynamic fields in the same -model class. Attributes for which there is a ``field`` declaration will be -treated according to the ``field`` declaration, with remaining attributes -being treated as dynamic fields. - -Attribute values in the dynamic fields must initially be set by either -passing the attribute hash to the constructor, mass assignment via -``attributes=``, mass assignment via ``[]=``, using ``write_attribute``, -or they must already be present in the database. - -.. code-block:: ruby - - # OK - bob = Person.new(name: 'Bob') - - # OK - bob = Person.new - bob.attributes = {age: 42} - - # OK - bob = Person.new - bob['age'] = 42 - - # Raises NoMethodError: undefined method age= - bob = Person.new - bob.age = 42 - - # OK - bob = Person.new - # OK - string access - bob.write_attribute('age', 42) - # OK - symbol access - bob.write_attribute(:name, 'Bob') - - # OK, initializes attributes from whatever is in the database - bob = Person.find('123') - -If an attribute is not present in a particular model instance's attributes -hash, both the reader and the writer for the corresponding field are not -defined, and invoking them raises ``NoMethodError``: - -.. code-block:: ruby - - bob = Person.new - bob.attributes = {age: 42} - - bob.age - # => 42 - - # raises NoMethodError - bob.name - - # raises NoMethodError - bob.name = 'Bob' - - # OK - bob['name'] = 'Bob' - - bob.name - # => "Bob" - -Attributes can always be read using mass attribute access or ``read_attribute`` -(this applies to models not using dynamic fields as well): - -.. code-block:: ruby - - bob = Person.new(age: 42) - - # OK - string access - bob['name'] - # => nil - - # OK - symbol access - bob[:name] - # => nil - - # OK - string access - bob['age'] - # => 42 - - # OK - symbol access - bob[:age] - # => 42 - - # OK - bob.attributes['name'] - # => nil - - # OK - bob.attributes['age'] - # => 42 - - # Returns nil - keys are always strings - bob.attributes[:age] - # => nil - - # OK - bob.read_attribute('name') - # => nil - - # OK - bob.read_attribute(:name) - # => nil - - # OK - string access - bob.read_attribute('age') - # => 42 - - # OK - symbol access - bob.read_attribute(:age) - # => 42 - -.. note:: - - The values returned from the ``read_attribute`` method, and those stored in - the ``attributes`` hash, are the ``mongoized`` values. - - -Special Characters in Field Names ---------------------------------- - -Mongoid permits dynamic field names to include spaces and punctuation: - -.. code-block:: ruby - - bob = Person.new('hello world' => 'MDB') - bob.send('hello world') - # => "MDB" - - bob.write_attribute("hello%world", 'MDB') - bob[:"hello%world"] - # => "MDB" - - -.. _localized-fields: - -Localized Fields -================ - -Mongoid supports localized fields via the `I18n gem `_. - -.. code-block:: ruby - - class Product - include Mongoid::Document - field :description, type: String, localize: true - end - -By telling the field to ``localize``, Mongoid will under the covers store the field -as a hash of locale/value pairs, but normal access to it will behave like a string. - -.. code-block:: ruby - - I18n.default_locale = :en - product = Product.new - product.description = "Marvelous!" - I18n.locale = :de - product.description = "Fantastisch!" - - product.attributes - # { "description" => { "en" => "Marvelous!", "de" => "Fantastisch!" } - -You can get and set all the translations at once by using the corresponding ``_translations`` method. - -.. code-block:: ruby - - product.description_translations - # { "en" => "Marvelous!", "de" => "Fantastisch!" } - product.description_translations = - { "en" => "Marvelous!", "de" => "Wunderbar!" } - -Localized fields can be used with any field type. For example, they can be used -with float fields for differences with currency: - -.. code:: ruby - - class Product - include Mongoid::Document - - field :price, type: Float, localize: true - field :currency, type: String, localize: true - end - -By creating the model in this way, we can separate the price from the currency -type, which allows you to use all of the number-related functionalities on the -price when querying or aggregating that field (provided that you index into the -stored translations hash). We can create an instance of this model as follows: - -.. code:: ruby - - product = Product.new - I18n.locale = :en - product.price = 1.00 - product.currency = "$" - I18n.locale = :he - product.price = 3.24 - product.currency = "₪" - - product.attributes - # => { "price" => { "en" => 1.0, "he" => 3.24 }, "currency" => { "en" => "$", "he" => "₪" } } - - -.. _present-fields: - -Localize ``:present`` Field Option ----------------------------------- - -Mongoid supports the ``:present`` option when creating a localized field: - -.. code-block:: ruby - - class Product - include Mongoid::Document - field :description, localize: :present - end - -This option automatically removes ``blank`` values (i.e. those that return true -for the ``blank?`` method) from the ``_translations`` hash: - -.. code-block:: ruby - - I18n.default_locale = :en - product = Product.new - product.description = "Marvelous!" - I18n.locale = :de - product.description = "Fantastisch!" - - product.description_translations - # { "en" => "Marvelous!", "de" => "Fantastisch!" } - - product.description = "" - product.description_translations - # { "en" => "Marvelous!" } - -When the empty string is written for the ``:de`` locale, the ``"de"`` key is -removed from the ``_translations`` hash instead of writing the empty string. - - -Fallbacks ---------- - -Mongoid integrates with -`i18n fallbacks `_. -To use the fallbacks, the respective functionality must be explicitly enabled. - -In a Rails application, set the ``config.i18n.fallbacks`` configuration setting -to ``true`` in your environment and specify the fallback languages: - -.. code-block:: ruby - - config.i18n.fallbacks = true - config.after_initialize do - I18n.fallbacks[:de] = [ :en, :es ] - end - -In a non-Rails application, include the fallbacks module into the I18n backend -you are using and specify the fallback languages: - -.. code-block:: ruby - - require "i18n/backend/fallbacks" - I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) - I18n.fallbacks[:de] = [ :en, :es ] - -When fallbacks are enabled, if a translation is not present in the active -language, translations will be looked up in the fallback languages: - -.. code-block:: ruby - - product = Product.new - I18n.locale = :en - product.description = "Marvelous!" - I18n.locale = :de - product.description # "Marvelous!" - -Mongoid also defines a ``:fallbacks`` option on fields, which can be used to -disable fallback functionality on a specific field: - -.. code:: ruby - - class Product - include Mongoid::Document - field :description, type: String, localize: true, fallbacks: false - end - - product = Product.new - I18n.locale = :en - product.description = "Marvelous!" - I18n.locale = :de - product.description # nil - -Note that this option defaults to ``true``. - -.. note:: - - In i18n 1.1, the behavior of fallbacks `changed `_ - to always require an explicit list of fallback locales rather than falling - back to the default locale when no fallback locales have been provided. - - -Querying --------- - -When querying for localized fields using Mongoid's criteria API, Mongoid will automatically -alter the criteria to match the current locale. - -.. code-block:: ruby - - # Match all products with Marvelous as the description. Locale is en. - Product.where(description: "Marvelous!") - # The resulting MongoDB query filter: { "description.en" : "Marvelous!" } - - -Indexing --------- - -If you plan to be querying extensively on localized fields, you should index each of the -locales that you plan on searching on. - -.. code-block:: ruby - - class Product - include Mongoid::Document - field :description, localize: true - - index "description.de" => 1 - index "description.en" => 1 - end - - -.. _read-only: - -Read-Only Attributes -==================== - -You can tell Mongoid that certain attributes are read-only. This will allow -documents to be created with these attributes, but changes to them will be -ignored when using mass update methods such as ``update_attributes``: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :origin, type: String - - attr_readonly :name, :origin - end - - band = Band.create(name: "Placebo") - band.update_attributes(name: "Tool") # Filters out the name change. - -If you explicitly try to update or remove a read-only attribute by itself, -a ``ReadonlyAttribute`` exception will be raised: - -.. code-block:: ruby - - band.update_attribute(:name, "Tool") # Raises the error. - band.remove_attribute(:name) # Raises the error. - -Assignments to read-only attributes using their setters will be ignored: - -.. code-block:: ruby - - b = Band.create!(name: "The Rolling Stones") - # => # - b.name = "The Smashing Pumpkins" - # => "The Smashing Pumpkins" - b.name - # => "The Rolling Stones" - -Calls to atomic persistence operators, like ``bit`` and ``inc``, will persist -changes to read-only fields. - -Timestamp Fields -================ - -Mongoid supplies a timestamping module in ``Mongoid::Timestamps`` which -can be included to get basic behavior for ``created_at`` and -``updated_at`` fields. - -.. code-block:: ruby - - class Person - include Mongoid::Document - include Mongoid::Timestamps - end - -You may also choose to only have specific timestamps for creation or -modification. - -.. code-block:: ruby - - class Person - include Mongoid::Document - include Mongoid::Timestamps::Created - end - - class Post - include Mongoid::Document - include Mongoid::Timestamps::Updated - end - -If you want to turn off timestamping for specific calls, use the timeless -method: - -.. code-block:: ruby - - person.timeless.save - Person.timeless.create! - -If you'd like shorter timestamp fields with aliases on them to save space, -you can include the short versions of the modules. - -.. code-block:: ruby - - class Band - include Mongoid::Document - include Mongoid::Timestamps::Short # For c_at and u_at. - end - - class Band - include Mongoid::Document - include Mongoid::Timestamps::Created::Short # For c_at only. - end - - class Band - include Mongoid::Document - include Mongoid::Timestamps::Updated::Short # For u_at only. - end - - -.. _field-names-with-periods-and-dollar-signs: - -Field Names with Dots/Periods (``.``) and Dollar Signs (``$``) -============================================================== - -Using dots/periods (``.``) in fields names and starting a field name with -a dollar sign (``$``) is not recommended, as Mongoid provides limited support -for retrieving and operating on the documents stored in those fields. - -Both Mongoid and MongoDB query language (MQL) generally use the dot/period -character (``.``) to separate field names in a field path that traverses -embedded documents, and words beginning with the dollar sign (``$``) as -operators. MongoDB provides `limited support -`_ -for using field names containing dots and starting with the dollar sign -for interoperability with other software, -however, due to this support being confined to specific operators -(e.g. :manual:`getField `, -:manual:`setField `) and -requiring the usage of the aggregation pipeline for both queries and updates, -applications should avoid using dots in field names and starting field names -with the dollar sign if possible. - -Mongoid, starting in version 8, now allows users to access fields that begin with -dollar signs and that contain dots/periods. They can be accessed using the ``send`` -method as follows: - -.. code:: - - class User - include Mongoid::Document - field :"first.last", type: String - field :"$_amount", type: Integer - end - - user = User.first - user.send(:"first.last") - # => Mike.Trout - user.send(:"$_amount") - # => 42650000 - -It is also possible to use ``read_attribute`` to access these fields: - -.. code:: - - user.read_attribute("first.last") - # => Mike.Trout - -Due to `server limitations `_, -updating and replacing fields containing dots and dollars requires using special -operators. For this reason, calling setters on these fields is prohibited and -will raise an error: - -.. code:: - - class User - include Mongoid::Document - field :"first.last", type: String - field :"$_amount", type: Integer - end - - user = User.new - user.send(:"first.last=", "Shohei.Ohtani") - # raises a InvalidDotDollarAssignment error - user.send(:"$_amount=", 8500000) - # raises a InvalidDotDollarAssignment error - diff --git a/docs/reference/indexes.txt b/docs/reference/indexes.txt deleted file mode 100644 index 7a5d11a475..0000000000 --- a/docs/reference/indexes.txt +++ /dev/null @@ -1,278 +0,0 @@ -.. _indexes: - -**************** -Index Management -**************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Specifying Indexes -================== - -You can define indexes on documents using the index macro. Provide the key for -the index along with a direction. Additional options can be supplied in the -second options hash parameter: - -.. code-block:: ruby - - class Person - include Mongoid::Document - field :ssn - - index({ ssn: 1 }, { unique: true, name: "ssn_index" }) - end - -You can define indexes on embedded document fields as well: - -.. code-block:: ruby - - class Person - include Mongoid::Document - embeds_many :addresses - index "addresses.street" => 1 - end - -You can index on multiple fields and provide direction: - -.. code-block:: ruby - - class Person - include Mongoid::Document - field :first_name - field :last_name - - index({ first_name: 1, last_name: 1 }, { unique: true }) - end - -Indexes can be sparse: - -.. code-block:: ruby - - class Person - include Mongoid::Document - field :ssn - - index({ ssn: -1 }, { sparse: true }) - end - -For geospatial indexes, make sure the field being indexed is of type Array: - -.. code-block:: ruby - - class Person - include Mongoid::Document - field :location, type: Array - - index({ location: "2d" }, { min: -200, max: 200 }) - end - -Indexes can be scoped to a specific database: - -.. code-block:: ruby - - class Person - include Mongoid::Document - field :ssn - index({ ssn: 1 }, { database: "users", unique: true, background: true }) - end - -You may use aliased field names in index definitions. Field aliases -will also be resolved on the following options: ``partial_filter_expression``, -``weights``, ``wildcard_projection``. - -.. code-block:: ruby - - 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. - -Mongoid can define indexes on "foreign key" fields for associations. -This only works on the association macro that the foreign key is stored on: - -.. code-block:: ruby - - class Comment - include Mongoid::Document - belongs_to :post, index: true - has_and_belongs_to_many :preferences, index: true - end - -*Deprecated:* In MongoDB 4.0 and earlier, users could control whether to build indexes -in the foreground (blocking) or background (non-blocking, but less efficient) using the -``background`` option. - -.. code-block:: ruby - - class Person - include Mongoid::Document - field :ssn - index({ ssn: 1 }, { unique: true, background: true }) - end - -The default value of ``background`` is controlled by Mongoid's -``background_indexing`` :ref:`configuration option `. - -The ``background`` option has `no effect as of MongoDB 4.2 -`_. - - -Specifying Search Indexes on MongoDB Atlas -========================================== - -If your application is connected to MongoDB Atlas, you can declare and manage -search indexes on your models. (This feature is only available on MongoDB -Atlas.) - -To declare a search index, use the ``search_index`` macro in your model: - -.. code-block:: ruby - - class Message - include Mongoid::Document - - search_index { ... } - search_index :named_index, { ... } - end - -Search indexes may be given an explicit name; this is necessary if you have -more than one search index on a model. - - -Index Management Rake Tasks -=========================== - -When you want to create the indexes in the database, use the provided -``db:mongoid:create_indexes`` Rake task: - -.. code-block:: bash - - $ rake db:mongoid:create_indexes - -Mongoid also provides a Rake task to delete all secondary indexes. - -.. code-block:: bash - - $ rake db:mongoid:remove_indexes - -Note: the output of these Rake tasks goes to the default logger configured -by Rails. This is usually a file like ``log/development.log`` and not standard -output. - -These create/remove indexes commands also works for just one model by running -in Rails console: - -.. code-block:: ruby - - # Create indexes for Model - Model.create_indexes - - # Remove indexes for Model - Model.remove_indexes - -Managing Search Indexes on MongoDB Atlas ----------------------------------------- - -If you have defined search indexes on your model, there are rake tasks available -for creating and removing those search indexes: - -.. code-block:: bash - - $ rake db:mongoid:create_search_indexes - $ rake db:mongoid:remove_search_indexes - -By default, creating search indexes will wait for the indexes to be created, -which can take quite some time. If you want to simply let the database create -the indexes in the background, you can set the ``WAIT_FOR_SEARCH_INDEXES`` -environment variable to 0, like this: - -.. code-block:: bash - - $ rake WAIT_FOR_SEARCH_INDEXES=0 db:mongoid:create_search_indexes - -Note that the task for removing search indexes will remove all search indexes -from all models, and should be used with caution. - -You can also add and remove search indexes for a single model by invoking the -following in a Rails console: - -.. code-block:: ruby - - # Create all defined search indexes on the model; this will return - # immediately and the indexes will be created in the background. - Model.create_search_indexes - - # Remove all search indexes from the model - Model.remove_search_indexes - - # Enumerate all search indexes on the model - Model.search_indexes.each { |index| ... } - - -Telling Mongoid Where to Look For Models ----------------------------------------- - -For non-Rails applications, Mongoid's rake tasks will look for models in -``./app/models`` and ``./lib/models``. For Rails, Mongoid will look in -``./app/models`` (or wherever you've configured Rails to look for models). If -your models are in another location, you will need to tell Mongoid where to -look for them with ``Mongoid.model_paths=``. You can do this by setting it -in your application's Rakefile: - -.. code-block:: ruby - - # Rakefile - - # keep the defaults, but add more paths to look for models - Mongoid.model_paths += [ "./src/models", "./lib/documents" ] - - # or, override the defaults entirely - Mongoid.model_paths = [ "./src/models", "./lib/documents" ] - -Make sure that these paths are in your application's load path, as well. For -example: - -.. code-block:: ruby - - # Rakefile - - $LOAD_PATHS.concat [ "./src/models", "./lib/documents" ] - - -Using Rake Tasks With Non-Rails Applications --------------------------------------------- - -Mongoid's Rake tasks are automatically loaded in Rails applications using -Mongoid. When using Mongoid with a non-Rails application, these tasks must -be loaded manually: - -.. code-block:: ruby - - # Rakefile - - require 'mongoid' - load 'mongoid/tasks/database.rake' - -If your application uses Bundler, you can require ``bundler/setup`` instead of -explicitly requiring ``mongoid``: - -.. code-block:: ruby - - # Rakefile - - require 'bundler/setup' - load 'mongoid/tasks/database.rake' diff --git a/docs/reference/inheritance.txt b/docs/reference/inheritance.txt deleted file mode 100644 index dcba02a96b..0000000000 --- a/docs/reference/inheritance.txt +++ /dev/null @@ -1,308 +0,0 @@ -.. _inheritance: - -*********** -Inheritance -*********** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -.. _inheritance-overview: - -Overview -======== - -Mongoid supports inheritance in both top level and embedded documents. When -a child document inherits from a parent document, the parent document's -fields, associations, validations and scopes are copied to the child document. - -.. code-block:: ruby - - class Canvas - include Mongoid::Document - field :name, type: String - embeds_many :shapes - end - - class Browser < Canvas - field :version, type: Integer - scope :recent, ->{ where(:version.gt => 3) } - end - - class Firefox < Browser - end - - class Shape - include Mongoid::Document - field :x, type: Integer - field :y, type: Integer - embedded_in :canvas - end - - class Circle < Shape - field :radius, type: Float - end - - class Rectangle < Shape - field :width, type: Float - field :height, type: Float - end - -In the above example, ``Canvas``, ``Browser`` and ``Firefox`` will all save in the canvases -collection. An additional attribute ``_type`` is stored in order to make sure when loaded -from the database the correct document is returned. This also holds true for the embedded -documents ``Circle``, ``Rectangle``, and ``Shape``. - -.. note:: - - When searching for a ``Circle``, the query will only return documents in the shape collection - where the ``_type`` (or whatever the discriminator key was set to) field has the value ``Circle`` (or - whatever the discriminator value was set to), all other discriminator values will be considered an object - of the Shape class. - - Similarly, when querying by parent classes (``Canvas`` in this example), any documents in the collection - that do not have a discriminator value, or whose discriminator value does not map to either the parent - or any of its descendants, will be returned as instances of the parent class. - - -.. _discriminator-key: - -Changing the Discriminator Key -============================== - -Mongoid supports changing the discriminator key from the default ``_type``. There are a few -cases where one might want to do this: - -1. For optimization: The user might want to use a shorter key like ``_t``. - -2. When trying to work with an existing system: It's possible the user is working with an existing system or dataset that has predefined keys. - - -There are two ways to change the discriminator key, on the class level and on the global level. -To change the discriminator key on the class level the user can set it directly on the parent class using -the ``discriminator_key=`` method. -Take the above example: - -.. code-block:: ruby - - class Shape - include Mongoid::Document - field :x, type: Integer - field :y, type: Integer - embedded_in :canvas - - self.discriminator_key = "shape_type" - end - - class Circle < Shape - field :radius, type: Float - end - - class Rectangle < Shape - field :width, type: Float - field :height, type: Float - end - -Here a call to the ``discriminator_key=`` setter was added to the parent class. Now, on -creation of a Rectangle or Circle, a ``shape_type`` field will be added. - -Note that the discriminator key can only be modified in the parent class, and an error -will be raised if trying to set it on the child class. - -If the discriminator key is changed after the child class is created, a new field is -added with the new discriminator key value, and the old field will remain unchanged. -For example: - -.. code-block:: ruby - - class Shape - include Mongoid::Document - field :x, type: Integer - field :y, type: Integer - embedded_in :canvas - end - - class Circle < Shape - field :radius, type: Float - end - - class Rectangle < Shape - field :width, type: Float - field :height, type: Float - end - - Shape.discriminator_key = "shape_type" - -In this case, on creation of a Rectangle or Circle, there will be both a ``shape_type`` -and a ``_type`` field that both default to ``Rectangle`` or ``Circle`` respectively. - - -The discriminator key can also be set on the global level. Meaning, all classes will -use the globally set discriminator key instead of ``_type``. Take the above example: - -.. code-block:: ruby - - Mongoid.discriminator_key = "_the_type" - - class Shape - include Mongoid::Document - field :x, type: Integer - field :y, type: Integer - embedded_in :canvas - end - - class Circle < Shape - field :radius, type: Float - end - - class Rectangle < Shape - field :width, type: Float - field :height, type: Float - end - -After setting the global discriminator key, all classes will use ``_the_type`` as -the discriminator key and will not contain a ``_type`` field. - -Note that when defining the discriminator key on the global level, it must be set before the -child class is defined for the child class to use that global value. -On the global level, however, if the user does not set the discriminator key before defining a child -class, the discriminator field will use the default ``_type`` and not the new global setting in -that child class. - - -.. _discriminator-value: - -Changing the Discriminator Value -================================ - -Mongoid also supports changing the discriminator value from the default value, which is the class name. -One can change the discriminator value by using the ``discriminator_value=`` method on that specific class. - -Take the above example: - -.. code-block:: ruby - - class Shape - include Mongoid::Document - field :x, type: Integer - field :y, type: Integer - embedded_in :canvas - end - - class Circle < Shape - field :radius, type: Float - - self.discriminator_value = "round thing" - end - - class Rectangle < Shape - field :width, type: Float - field :height, type: Float - end - -Here, a call to the ``discriminator_value=`` setter was added to ``Circle``. -Now, on creation of a ``Circle``, the document will contain a field with the key ``_type`` (or whatever the ``discriminator_key`` was changed to) -and the value "round thing." - -.. note:: - - Because the discriminator value overrides are declared in child classes, - the child classes potentially found by a query must be loaded prior to - sending that query. In the above example, the ``Circle`` class definition - must be loaded when querying on ``Shape`` if the returned documents could - potentially be instances of ``Circle`` (since autoloading wouldn't resolve - ``"round thing"`` to ``Circle``). - - -Querying Subclasses -=================== - -Querying for subclasses is handled in the normal manner, and although the documents are -all in the same collection, queries will only return documents of the correct type, -similar to Single Table Inheritance in ActiveRecord. - -.. code-block:: ruby - - # Returns Canvas documents and subclasses - Canvas.where(name: "Paper") - # Returns only Firefox documents - Firefox.where(name: "Window 1") - - -Associations -============ - -You can add any type of subclass to a has one or has many association, through -either normal setting or through the build and create methods on the association: - -.. code-block:: ruby - - firefox = Firefox.new - # Builds a Shape object - firefox.shapes.build({ x: 0, y: 0 }) - # Builds a Circle object - firefox.shapes.build({ x: 0, y: 0 }, Circle) - # Creates a Rectangle object - firefox.shapes.create({ x: 0, y: 0 }, Rectangle) - - rect = Rectangle.new(width: 100, height: 200) - firefox.shapes - - -.. _inheritance-persistence-context: - -Persistence Contexts -==================== - -Mongoid allows the persistence context of a subclass to be changed from the -persistence context of its parent. This means that, using the ``store_in`` -method, we can store the documents of the subclasses in different collections -(as well as different databases, clients) than their parents: - -.. code:: ruby - - class Shape - include Mongoid::Document - store_in collection: :shapes - end - - class Circle < Shape - store_in collection: :circles - end - - class Square < Shape - store_in collection: :squares - end - - Shape.create! - Circle.create! - Square.create! - -Setting the collection on the children causes the documents for those children -to be stored in the set collection, instead of in the parent's collection: - -.. code:: javascript - - > db.shapes.find() - { "_id" : ObjectId("62fe9a493282a43d6b725e10"), "_type" : "Shape" } - > db.circles.find() - { "_id" : ObjectId("62fe9a493282a43d6b725e11"), "_type" : "Circle" } - > db.squares.find() - { "_id" : ObjectId("62fe9a493282a43d6b725e12"), "_type" : "Square" } - -If the collection is set on some of the subclasses and not others, the subclasses -with set collections will store documents in those collections, and the -subclasses without set collections will be store documents in the parent's -collection. - -.. note:: - - Note that changing the collection that a subclass is stored in will cause - documents of that subclass to no longer be found in the results of querying - its parent class. diff --git a/docs/reference/map-reduce.txt b/docs/reference/map-reduce.txt deleted file mode 100644 index 2251ffa915..0000000000 --- a/docs/reference/map-reduce.txt +++ /dev/null @@ -1,139 +0,0 @@ -.. _map-reduce: - -********** -Map/Reduce -********** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -Mongoid provides a DSL around MongoDB's map/reduce framework, for performing -custom map/reduce jobs or simple aggregations. - -.. note:: - - The map-reduce operation is deprecated. - The :ref:`aggregation framework ` provides better - performance and usability than map-reduce operations, and should be - preferred for new development. - -Execution ---------- - -You can tell Mongoid off the class or a criteria to perform a map/reduce -by calling ``map_reduce`` and providing map and reduce javascript -functions. - -.. code-block:: ruby - - map = %Q{ - function() { - emit(this.name, { likes: this.likes }); - } - } - - reduce = %Q{ - function(key, values) { - var result = { likes: 0 }; - values.forEach(function(value) { - result.likes += value.likes; - }); - return result; - } - } - - Band.where(:likes.gt => 100).map_reduce(map, reduce).out(inline: 1) - -Just like criteria, map/reduce calls are lazily evaluated. So nothing will -hit the database until you iterate over the results, or make a call on the -wrapper that would need to force a database hit. - -.. code-block:: ruby - - Band.map_reduce(map, reduce).out(replace: "mr-results").each do |document| - p document # { "_id" => "Tool", "value" => { "likes" => 200 }} - end - -The only required thing you provide along with a map/reduce is where to -output the results. If you do not provide this an error will be raised. -Valid options to ``#out`` are: - -- ``inline: 1``: Don't store the output in a collection. -- ``replace: "name"``: Store in a collection with the - provided name, and overwrite any documents that exist in it. -- ``merge: "name"``: Store in a collection with the - provided name, and merge the results with the existing documents. -- ``reduce: "name"``: Store in a collection with the - provided name, and reduce all existing results in that collection. - -Raw Results ------------ - -Results of Map/Reduce execution can be retrieved via the ``execute`` method -or its aliases ``raw`` and ``results``: - -.. code-block:: ruby - - mr = Band.where(:likes.gt => 100).map_reduce(map, reduce).out(inline: 1) - - mr.execute - # => {"results"=>[{"_id"=>"Tool", "value"=>{"likes"=>200.0}}], - "timeMillis"=>14, - "counts"=>{"input"=>4, "emit"=>4, "reduce"=>1, "output"=>1}, - "ok"=>1.0, - "$clusterTime"=>{"clusterTime"=>#, "signature"=>{"hash"=>, "keyId"=>0}}, - "operationTime"=>#} - - -Statistics ----------- - -MongoDB servers 4.2 and lower provide Map/Reduce execution statistics. As of -MongoDB 4.4, Map/Reduce is implemented via the aggregation pipeline and -statistics described in this section are not available. - -The following methods are provided on the ``MapReduce`` object: - -- ``counts``: Number of documents read, emitted, reduced and output through - the pipeline. -- ``input``, ``emitted``, ``reduced``, ``output``: individual count methods. - Note that ``emitted`` and ``reduced`` methods are named differently from - hash keys in ``counts``. -- ``time``: The time, in milliseconds, that Map/Reduce pipeline took to execute. - -The following code illustrates retrieving the statistics: - -.. code-block:: ruby - - mr = Band.where(:likes.gt => 100).map_reduce(map, reduce).out(inline: 1) - - mr.counts - # => {"input"=>4, "emit"=>4, "reduce"=>1, "output"=>1} - - mr.input - # => 4 - - mr.emitted - # => 4 - - mr.reduced - # => 1 - - mr.output - # => 1 - - mr.time - # => 14 - -.. note:: - - Each statistics method invocation re-executes the Map/Reduce pipeline. - The results of execution are not stored by Mongoid. Consider using the - ``execute`` method to retrieve the raw results and obtaining the statistics - from the raw results if multiple statistics are desired. diff --git a/docs/reference/nested-attributes.txt b/docs/reference/nested-attributes.txt deleted file mode 100644 index 5803206ec8..0000000000 --- a/docs/reference/nested-attributes.txt +++ /dev/null @@ -1,140 +0,0 @@ -.. _nested-attributes: - -***************** -Nested Attributes -***************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Nested attributes provide a mechanism for updating documents and their -associations in a single operation by nesting attributes in a single -parameters hash. This is useful when wanting to edit multiple documents -within a single web form. - -Behavior -======== - -Nested attributes can be enabled for any association, embedded or referenced. -To enable this for an association, simply provide the association name to the -``accepts_nested_attributes_for`` macro. - -.. code-block:: ruby - - class Band - include Mongoid::Document - embeds_many :albums - belongs_to :producer - accepts_nested_attributes_for :albums, :producer - end - -Note that when you add nested attributes functionality to a referenced -association, Mongoid will automatically enable autosave for that association. - -When an association gains nested attributes behavior, an additional method is -added to the base model, which should be used to update the attributes with -the new functionality. This method is the association name plus ``_attributes=``. -You can use this method directly, or more commonly the name of the method can -be an attribute in the updates for the base class, in which case -Mongoid will call the appropriate setter under the covers. - -.. code-block:: ruby - - band = Band.first - band.producer_attributes = { name: "Flood" } - band.attributes = { producer_attributes: { name: "Flood" }} - -Note that this will work with any attribute based setter method in Mongoid, -including ``update``, ``update_attributes`` and ``attributes=``, as well as -``create`` (and all of their corresponding bang methods). For example, creating -a new person with associated address records can be done in a single -statement, like this: - -.. code-block:: ruby - - person = Person.create( - name: 'John Schmidt', - addresses_attributes: [ - { type: 'home', street: '1234 Street Ave.', city: 'Somewhere' }, - { type: 'work', street: 'Parkway Blvd.', city: 'Elsewehre' }, - ]) - - -Creating Records ----------------- - -You can create new nested records via nested attributes by omitting -an ``_id`` field: - -.. code-block:: ruby - - person = Person.first - person.update(addresses_attributes: [ - { type: 'prior', street: '221B Baker St', city: 'London' } ]) - -This will append the new record to the existing set; existing records will -not be changed. - - -Updating Records ----------------- - -If you specify an ``_id`` field for any of the nested records, the attributes -will be used to update the record with that id: - -.. code-block:: ruby - - person = Person.first - address = person.addresses.first - person.update(addresses_attributes: [ - { _id: address._id, city: 'Lisbon' } ]) - -Note that if there is no record with that id, a ``Mongoid::Errors::DocumentNotFound`` -exception will be raised. - - -Destroying Records ------------------- - -You can also destroy records this way, by specifying a special -``_destroy`` attribute. In order to use this, you must have passed -``allow_destroy: true`` with the ``accepts_nested_attributes_for`` -declaration: - -.. code-block:: ruby - - class Person - # ... - - accepts_nested_attributes_for :addresses, allow_destroy: true - end - - person = Person.first - address = person.addresses.first - person.update(addresses_attributes: [ - { _id: address._id, _destroy: true } ]) - -Note that, as with updates, if there is no record with that id, -a ``Mongoid::Errors::DocumentNotFound`` exception will be raised. - - -Combining Operations --------------------- - -Nested attributes allow you to combine all of these operations in -a single statement! Here's an example that creates an address, -updates another address, and destroys yet another address, all in -a single command: - -.. code-block:: ruby - - person = Person.first - person.update(addresses_attributes: [ - { type: 'alt', street: '1234 Somewhere St.', city: 'Cititon' }, - { _id: an_address_id, city: 'Changed City' }, - { _id: another_id, _destroy: true } ]) diff --git a/docs/reference/persistence-configuration.txt b/docs/reference/persistence-configuration.txt deleted file mode 100644 index 6712fb5519..0000000000 --- a/docs/reference/persistence-configuration.txt +++ /dev/null @@ -1,268 +0,0 @@ -.. _persistence: - -************************* -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(...) diff --git a/docs/reference/queries.txt b/docs/reference/queries.txt deleted file mode 100644 index 0ef52259e7..0000000000 --- a/docs/reference/queries.txt +++ /dev/null @@ -1,2480 +0,0 @@ -.. _queries: - -******* -Queries -******* - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -Mongoid provides a rich query DSL inspired by ActiveRecord. A trivial query -looks as follows: - -.. code-block:: ruby - - Band.where(name: "Depeche Mode") - -A more complex query utilizing various Mongoid features could be as follows: - -.. code-block:: ruby - - Band. - where(:founded.gte => "1980-01-01"). - in(name: [ "Tool", "Deftones" ]). - union. - in(name: [ "Melvins" ]) - -The query methods return ``Mongoid::Criteria`` objects, which are chainable -and lazily evaluated wrappers for MongoDB query language (MQL). -The queries are executed when their result sets are iterated. For example: - -.. code-block:: ruby - - # Construct a Criteria object: - - Band.where(name: 'Deftones') - # => #"Deftones"} - # options: {} - # class: Band - # embedded: false> - - # Evaluate the query and get matching documents: - - Band.where(name: 'Deftones').to_a - # => [#] - -Methods like ``first`` and ``last`` return the individual documents immediately. -Otherwise, iterating a Criteria object with methods like ``each`` or ``map`` -retrieves the documents from the server. ``to_a`` can be used to force -execution of a query that returns an array of documents, literally converting -a Criteria object to an Array. - -When a query method is called on a Criteria instance, the method returns a new -Criteria instance with the new conditions added to the existing conditions: - -.. code-block:: ruby - - scope = Band.where(:founded.gte => "1980-01-01") - # => #{"$gte"=>"1980-01-01"}} - # options: {} - # class: Band - # embedded: false> - - scope.where(:founded.lte => "2020-01-01") - # => #{"$gte"=>"1980-01-01", "$lte"=>"2020-01-01"}} - # options: {} - # class: Band - # embedded: false> - - scope - # => #{"$gte"=>"1980-01-01"}} - # options: {} - # class: Band - # embedded: false> - - -Condition Syntax -================ - -Mongoid supports three ways of specifying individual conditions: - -1. Field syntax. -2. MQL syntax. -3. Symbol operator syntax. - -All syntaxes support querying embedded documents using the dot notation. -All syntaxes respect field types, if the field being queried is defined in the -model class, and field aliases. - -The examples in this section use the following model definition: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :name, type: String - field :founded, type: Integer - field :m, as: :member_count, type: Integer - - embeds_one :manager - end - - class Manager - include Mongoid::Document - - embedded_in :band - - field :name, type: String - end - -Field Syntax ------------- - -The simplest querying syntax utilizes the basic Ruby hashes. Keys can be -symbols or strings, and correspond to field names in MongoDB documents: - -.. code-block:: ruby - - Band.where(name: "Depeche Mode") - # => #"Depeche Mode"} - # options: {} - # class: Band - # embedded: false> - - # Equivalent to: - - Band.where("name" => "Depeche Mode") - -MQL Syntax ----------- - -An MQL operator may be specified on any field using the hash syntax: - -.. code-block:: ruby - - Band.where(founded: {'$gt' => 1980}) - # => #{"$gt"=>1980}} - # options: {} - # class: Band - # embedded: false> - - # Equivalent to: - - Band.where('founded' => {'$gt' => 1980}) - -Symbol Operator Syntax ----------------------- - -MQL operators may be specified as methods on symbols for the respective field -name, as follows: - -.. code-block:: ruby - - Band.where(:founded.gt => 1980) - # => #{"$gt"=>1980}} - # options: {} - # class: Band - # embedded: false> - - -Fields -====== - -Querying on Defined Fields --------------------------- - -In order to query on a field, it is not necessary to add the field to -:ref:`the model class definition `. However, if a field is defined in -the model class, Mongoid will coerce query values to match defined field types -when constructing the query: - -.. code-block:: ruby - - Band.where(name: 2020, founded: "2020") - # => #"2020", "founded"=>2020} - # options: {} - # class: Band - # embedded: false> - -Querying for Raw Values ------------------------ - -If you'd like to bypass Mongoid's query type coercion behavior and query -directly for the raw-typed value in the database, wrap the query value in -``Mongoid::RawValue`` class. This can be useful when working with legacy data. - -.. code-block:: ruby - - Band.where(founded: Mongoid::RawValue("2020")) - # => #"2020"} - # options: {} - # class: Band - # embedded: false> - -Field Aliases -------------- - -Queries take into account :ref:`storage field names ` -and :ref:`field aliases `: - -.. code-block:: ruby - - Band.where(name: 'Astral Projection') - # => #"Astral Projection"} - # options: {} - # class: Band - # embedded: false> - -Since ``id`` and ``_id`` fields are aliases, either one can be used for queries: - -.. code-block:: ruby - - Band.where(id: '5ebdeddfe1b83265a376a760') - # => #BSON::ObjectId('5ebdeddfe1b83265a376a760')} - # options: {} - # class: Band - # embedded: false> - - -Embedded Documents -================== - -To match values of fields of embedded documents, use the dot notation: - -.. code-block:: ruby - - Band.where('manager.name' => 'Smith') - # => #"Smith"} - # options: {} - # class: Band - # embedded: false> - - Band.where(:'manager.name'.ne => 'Smith') - # => #{"$ne"=>"Smith"}} - # options: {} - # class: Band - # embedded: false> - -.. note:: - - Queries always return top-level model instances, even if all of the - conditions are referencing embedded documents. - - -.. _logical-operations: - -Logical Operations -================== - -Mongoid supports ``and``, ``or``, ``nor`` and ``not`` logical operations on -``Criteria`` objects. These methods take one or more hash of conditions -or another ``Criteria`` object as their arguments, with ``not`` additionally -having an argument-free version. - -.. code-block:: ruby - - # and with conditions - Band.where(label: 'Trust in Trance').and(name: 'Astral Projection') - - # or with scope - Band.where(label: 'Trust in Trance').or(Band.where(name: 'Astral Projection')) - - # not with conditions - Band.not(label: 'Trust in Trance', name: 'Astral Projection') - - # argument-less not - Band.not.where(label: 'Trust in Trance', name: 'Astral Projection') - -For backwards compatibility with earlier Mongoid versions, all of the logical -operation methods also accept arrays of parameters, which will be flattened -to obtain the criteria. Passing arrays to logical operations is deprecated and -may be removed in a future version of Mongoid. - -The following calls all produce the same query conditions: - -.. code-block:: ruby - - # Condition hashes passed to separate and invocations - Band.and(name: 'SUN Project').and(member_count: 2) - - # Multiple condition hashes in the same and invocation - Band.and({name: 'SUN Project'}, {member_count: 2}) - - # Multiple condition hashes in an array - deprecated - Band.and([{name: 'SUN Project'}, {member_count: 2}]) - - # Condition hash in where and a scope - Band.where(name: 'SUN Project').and(Band.where(member_count: 2)) - - # Condition hash in and and a scope - Band.and({name: 'SUN Project'}, Band.where(member_count: 2)) - - # Scope as an array element, nested arrays - deprecated - Band.and([Band.where(name: 'SUN Project'), [{member_count: 2}]]) - - # All produce: - # => #"SUN Project", "member_count"=>2} - # options: {} - # class: Band - # embedded: false> - - -Operator Combinations ---------------------- - -As of Mongoid 7.1, logical operators (``and``, ``or``, ``nor`` and ``not``) -have been changed to have the the same semantics as `those of ActiveRecord -`_. -To obtain the semantics of ``or`` as it behaved in Mongoid 7.0 and earlier, -use ``any_of`` which is described below. - -When conditions are specified on the same field multiple times, all -conditions are added to the criteria: - -.. code-block:: ruby - - Band.where(name: 1).where(name: 2).selector - # => {"name"=>"1", "$and"=>[{"name"=>"2"}]} - - Band.where(name: 1).or(name: 2).selector - # => {"$or"=>[{"name"=>"1"}, {"name"=>"2"}]} - -``any_of``, ``none_of``, ``nor`` and ``not`` behave similarly, with ``not`` producing -different query shapes as described below. - -When ``and``, ``or`` and ``nor`` logical operators are used, they -operate on the criteria built up to that point and its argument. -``where`` has the same meaning as ``and``: - -.. code-block:: ruby - - # or joins the two conditions - Band.where(name: 'Sun').or(label: 'Trust').selector - # => {"$or"=>[{"name"=>"Sun"}, {"label"=>"Trust"}]} - - # or applies only to the first condition, the second condition is added - # to the top level as $and - Band.or(name: 'Sun').where(label: 'Trust').selector - # => {"$or"=>[{"name"=>"Sun"}], "label"=>"Trust"} - - # Same as previous example - where and and are aliases - Band.or(name: 'Sun').and(label: 'Trust').selector - # => {"$or"=>[{"name"=>"Sun"}], "label"=>"Trust"} - - # Same operator can be stacked any number of times - Band.or(name: 'Sun').or(label: 'Trust').selector - # => {"$or"=>[{"name"=>"Sun"}, {"label"=>"Trust"}]} - - # The label: Foo condition is added to the top level as $and - Band.where(name: 'Sun').or(label: 'Trust').where(label: 'Foo').selector - # => {"$or"=>[{"name"=>"Sun"}, {"label"=>"Trust"}], "label"=>"Foo"} - - -``and`` Behavior ----------------- - -The ``and`` method will add new simple conditions to the top level of the -criteria, unless the receiving criteria already has a condition on the -respective fields, in which case the conditions will be combined with ``$and``. - -.. code-block:: ruby - - Band.where(label: 'Trust in Trance').and(name: 'Astral Projection').selector - # => {"label"=>"Trust in Trance Records", "name"=>"Astral Projection"} - - Band.where(name: /Best/).and(name: 'Astral Projection').selector - # => {"name"=>/Best/, "$and"=>[{"name"=>"Astral Projection"}]} - -As of Mongoid 7.1, specifying multiple criteria on the same field with ``and`` -combines all criteria so specified, whereas in previous versions of Mongoid -conditions on a field sometimes replaced previously specified conditions on -the same field, depending on which form of ``and`` was used. - - -``or``/``nor`` Behavior -_---------------------- - -``or`` and ``nor`` produce ``$or`` and ``$nor`` MongoDB operators, respectively, -using the receiver and all of the arguments as operands. For example: - -.. code-block:: ruby - - Band.where(name: /Best/).or(name: 'Astral Projection') - # => {"$or"=>[{"name"=>/Best/}, {"name"=>"Astral Projection"}]} - - Band.where(name: /Best/).and(name: 'Astral Projection'). - or(Band.where(label: /Records/)).and(label: 'Trust').selector - # => {"$or"=>[{"name"=>/Best/, "$and"=>[{"name"=>"Astral Projection"}]}, {"label"=>/Records/}], "label"=>"Trust"} - -If the only condition on the receiver is another ``or``/``nor``, the new -conditions are added to the existing list: - -.. code-block:: ruby - - Band.where(name: /Best/).or(name: 'Astral Projection'). - or(Band.where(label: /Records/)).selector - # => {"$or"=>[{"name"=>/Best/}, {"name"=>"Astral Projection"}, {"label"=>/Records/}]} - -Use ``any_of`` to add a disjunction to a Criteria object while maintaining -all of the conditions built up so far as they are. - - -.. _any-of: - -``any_of`` Behavior -------------------- - -``any_of`` adds a disjunction built from its arguments to the existing -conditions in the criteria. For example: - -.. code-block:: ruby - - Band.where(label: /Trust/).any_of({name: 'Astral Projection'}, {name: /Best/}) - # => {"label"=>/Trust/, "$or"=>[{"name"=>"Astral Projection"}, {"name"=>/Best/}]} - -The conditions are hoisted to the top level if possible: - -.. code-block:: ruby - - Band.where(label: /Trust/).any_of({name: 'Astral Projection'}) - # => {"label"=>/Trust/, "name"=>"Astral Projection"} - - -.. _none-of: - -``none_of`` Behavior --------------------- - -``none_of`` adds a negated disjunction ("nor") built from its arguments to -the existing conditions in the criteria. For example: - -.. code-block:: ruby - - Band.where(label: /Trust/).none_of({name: 'Astral Projection'}, {name: /Best/}) - # => {"label"=>/Trust/, "$nor"=>[{"name"=>"Astral Projection"}, {"name"=>/Best/}]} - - -``not`` Behavior ----------------- - -``not`` method can be called without arguments, in which case it will negate -the next condition that is specified. ``not`` can also be called with one -or more hash conditions or ``Criteria`` objects, which will all be negated and -added to the criteria. - -.. code-block:: ruby - - # not negates subsequent where - Band.not.where(name: 'Best').selector - # => {"name"=>{"$ne"=>"Best"}} - - # The second where is added as $and - Band.not.where(name: 'Best').where(label: /Records/).selector - # => {"name"=>{"$ne"=>"Best"}, "label"=>/Records/} - - # not negates its argument - Band.not(name: 'Best').selector - # => {"name"=>{"$ne"=>"Best"}} - -.. note:: - - ``$not`` in MongoDB server cannot be used with a string argument. - Mongoid uses ``$ne`` operator to achieve such a negation: - - .. code-block:: ruby - - # String negation - uses $ne - Band.not.where(name: 'Best').selector - # => {"name"=>{"$ne"=>"Best"}} - - # Regexp negation - uses $not - Band.not.where(name: /Best/).selector - # => {"name"=>{"$not"=>/Best/}} - -Similarly to ``and``, ``not`` will negate individual conditions for simple -field criteria. For complex conditions and when a field already has a condition -defined on it, since MongoDB server only supports the ``$not`` operator on -a per-field basis rather than globally, Mongoid emulates ``$not`` by using -an ``{'$and' => [{'$nor' => ...}]}`` construct: - -.. code-block:: ruby - - # Simple condition - Band.not(name: /Best/).selector - # => {"name"=>{"$not"=>/Best/}} - - # Complex conditions - Band.where(name: /Best/).not(name: 'Astral Projection').selector - # => {"name"=>/Best/, "$and"=>[{"$nor"=>[{"name"=>"Astral Projection"}]}]} - - # Symbol operator syntax - Band.not(:name.ne => 'Astral Projection') - # => #[{"$nor"=>[{"name"=>{"$ne"=>"Astral Projection"}}]}]} - # options: {} - # class: Band - # embedded: false> - -If using ``not`` with arrays or regular expressions, please note the -caveats/limitations of ``$not`` `stated in the MongoDB server documentation -`_. - - -Incremental Query Construction -============================== - -By default, when conditions are added to a query, Mongoid considers each -condition complete and independent from any other conditions potentially -present in the query. For example, calling ``in`` twice adds two separate -``$in`` conditions: - -.. code-block:: ruby - - Band.in(name: ['a']).in(name: ['b']) - => #{"$in"=>["a"]}, "$and"=>[{"name"=>{"$in"=>["b"]}}]} - options: {} - class: Band - embedded: false> - -Some operator methods support building the condition incrementally. In this -case, when an condition on a field which uses one of the supported operators -is being added, if there already is a condition on the same field using the -same operator, the operator expressions are combined according to the -specified *merge strategy*. - -.. _merge-strategies: - -Merge Strategies ----------------- - -Mongoid provides three merge strategies: - -- **Override**: the new operator instance replaces any existing conditions on - the same field using the same operator. -- **Intersect**: if there already is a condition using the same operator on the - same field, the values of the existing condition are intersected with the - values of the new condition and the result is stored as the operator value. -- **Union**: if there already is a condition using the same operator on the - same field, the values of the new condition are added to the values of the - existing condition and the result is stored as the operator value. - -The following snippet demonstrates all of the strategies, using ``in`` as the -example operator: - -.. code-block:: ruby - - Band.in(name: ['a']).override.in(name: ['b']) - => #{"$in"=>["b"]}} - options: {} - class: Band - embedded: false> - - Band.in(name: ['a', 'b']).intersect.in(name: ['b', 'c']) - => #{"$in"=>["b"]}} - options: {} - class: Band - embedded: false> - - Band.in(name: ['a']).union.in(name: ['b']) - => #{"$in"=>["a", "b"]}} - options: {} - class: Band - embedded: false> - -The strategy is requested by calling ``override``, ``intersect`` or ``union`` -on a ``Criteria`` instance. The requested strategy applies to the next -condition method called on the query. If the next condition method called does -not support merge strategies, the strategy is reset, as shown in the following -example: - -.. code-block:: ruby - - Band.in(name: ['a']).union.ne(name: 'c').in(name: ['b']) - => #{"$in"=>["a"], "$ne"=>"c"}, "$and"=>[{"name"=>{"$in"=>["b"]}}]} - options: {} - class: Band - embedded: false> - -Since ``ne`` does not support merge strategies, the ``union`` strategy was -ignored and reset and when ``in`` was invoked the second time there was no -strategy active. - -.. warning:: - - Merge strategies currently assume the previous condition(s) have been added - to the top level of the query, however this is not always the case - (conditions may be nested under an ``$and`` clause). Using merge strategies - with complex criteria may cause incorrect queries to be constructed. - This misbehavior is `intended to be fixed in the future - `_. - - -Supported Operator Methods --------------------------- - -The following operator methods support merge strategies: - -- ``all`` -- ``in`` -- ``nin`` - -The set of methods may be expanded in future releases of Mongoid. For -future compatibility, only invoke a strategy method when the next method call -is an operator that supports merge strategies. - -Note that the merge strategies are currently only applied when conditions are -added through the designated methods. In the following example merge strategy -is not applied because the second condition is added via ``where``, not via -``in``: - -.. code-block:: ruby - - Band.in(foo: ['a']).union.where(foo: {'$in' => 'b'}) - => #{"$in"=>["a"]}, "$and"=>[{"foo"=>{"$in"=>"b"}}]} - options: {} - class: Band - embedded: false> - -This behavior may change in a future release of Mongoid and should not be -relied upon. - -In contrast, it does not matter how the existing query was built when a -merge strategy-supporting operator method is invoked. In the following -example, the first condition was added through ``where`` but the strategy -mechanism still applies: - -.. code-block:: ruby - - Band.where(foo: {'$in' => ['a']}).union.in(foo: ['b']) - => #{"$in"=>["a", "b"]}} - options: {} - class: Band - embedded: false> - -Operator Value Expansion ------------------------- - -Operator methods that support merge strategies all take ``Array`` as their value -type. Mongoid expands ``Array``-compatible types, such as a ``Range``, -when they are used with these operator methods: - -.. code-block:: ruby - - Band.in(year: 1950..1960) - => #{"$in"=>[1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960]}} - options: {} - class: Band - embedded: false> - -Additionally, Mongoid has historically wrapped non-``Array`` values in arrays, -as the following example demonstrates: - -.. code-block:: ruby - - Band.in(year: 1950) - => #{"$in"=>[1950]}} - options: {} - class: Band - embedded: false> - - -Query Methods -============= - -elem_match ----------- - -This matcher finds documents with array fields where one of the array values -matches all of the conditions. For example: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :tours, type: Array - end - - aerosmith = Band.create!(name: 'Aerosmith', tours: [ - {city: 'London', year: 1995}, - {city: 'New York', year: 1999}, - ]) - - Band.elem_match(tours: {city: 'London'}).to_a # => [aerosmith] - -``elem_match`` also works with embedded associations: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name, type: String - embeds_many :tours - end - - class Tour - include Mongoid::Document - field :city, type: String - field :year, type: Integer - embedded_in :band - end - - dm = Band.create!(name: 'Depeche Mode') - aerosmith = Band.create!(name: 'Aerosmith') - Tour.create!(band: aerosmith, city: 'London', year: 1995) - Tour.create!(band: aerosmith, city: 'New York', year: 1999) - - Band.elem_match(tours: {city: 'London'}).to_a # => [aerosmith] - -``elem_match`` does not work with non-embedded associations because MongoDB -does not have joins - the conditions would be added to the collection -that is the source of a non-embedded association rather than the collection -of the association's target. - -``elem_match`` can also be used with recursively embedded associations, -as the following example shows: - -.. code-block:: ruby - - class Tag - include Mongoid::Document - field :name, type: String - recursively_embeds_many - end - - root = Tag.create!(name: 'root') - sub1 = Tag.new(name: 'sub1', child_tags: [Tag.new(name: 'subsub1')]) - root.child_tags << sub1 - root.child_tags << Tag.new(name: 'sub2') - root.save! - - Tag.elem_match(child_tags: {name: 'sub1'}).to_a # => [root] - - root.child_tags.elem_match(child_tags: {name: 'subsub1'}).to_a # => [sub1] - - -.. _projection: - -Projection -========== - -Mongoid provides two projection operators: ``only`` and ``without``. - - -.. _only: - -``only`` --------- - -The ``only`` method retrieves only the specified fields from the database. This -operation is sometimes called "projection". - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :name, type: String - field :label, type: String - - embeds_many :tours - end - - class Tour - include Mongoid::Document - - field :city, type: String - field :year, type: Integer - - embedded_in :band - end - - band = Band.only(:name).first - -Attempting to reference attributes which have not been loaded results in -``Mongoid::Errors::AttributeNotLoaded``. - -.. code-block:: ruby - - band.label - #=> raises Mongoid::Errors::AttributeNotLoaded - -Even though Mongoid currently allows writing to attributes that have not -been loaded, such writes will not be persisted -(`MONGOID-4701 `_) and -should therefore be avoided. - -``only`` can also be used with embedded associations: - -.. code-block:: ruby - - band = Band.only(:name, 'tours.year').last - # => # - - band.tours.first - # => # - -.. note:: - - Server versions 4.2 and lower allowed projecting both an association and - the association's fields in the same query, as follows: - - .. code-block:: ruby - - band = Band.only(:tours, 'tours.year').last - - The most recent projection specification overrides the earlier one. - For example, the above query was equivalent to: - - .. code-block:: ruby - - band = Band.only('tours.year').last - - Server versions 4.4 and higher prohibit specifying an association and its - fields in projection in the same query. - -``only`` can be specified with referenced associations (has_one, has_many, -has_and_belongs_to_many) but is currently ignored for referenced associations - -all fields of referenced associations will be loaded -(`MONGOID-4704 `_). - -Note that if a document has ``has_one`` or ``has_and_belongs_to_many`` associations, -the fields with foreign keys must be included in the list of attributes -loaded with ``only`` for those associations to be loaded. For example: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :name, type: String - - has_and_belongs_to_many :managers - end - - class Manager - include Mongoid::Document - - has_and_belongs_to_many :bands - end - - band = Band.create!(name: 'Astral Projection') - band.managers << Manager.new - - Band.where(name: 'Astral Projection').only(:name).first.managers - # => [] - - Band.where(name: 'Astral Projection').only(:name, :manager_ids).first.managers - # => [#] - - -.. _without: - -``without`` ------------ - -The opposite of ``only``, ``without`` causes the specified fields to be omitted: - -.. code-block:: ruby - - Band.without(:name) - # => - # #{"name"=>0}} - # class: Band - # embedded: false> - -Because Mongoid requires the ``_id`` field for various operations, it (as well -as its ``id`` alias) cannot be omitted via ``without``: - -.. code-block:: ruby - - Band.without(:name, :id) - # => - # #{"name"=>0}} - # class: Band - # embedded: false> - - Band.without(:name, :_id) - # => - # #{"name"=>0}} - # class: Band - # embedded: false> - - -.. _ordering: - -Ordering -======== - -Mongoid provides the ``order`` method on ``Criteria`` objects and its alias, -``order_by``, to specify the ordering of documents. These methods take a -hash indicating which fields to order the documents by, and whether to use -ascending or descending order for each field. - -.. code-block:: ruby - - Band.order(name: 1) - # => #{"name"=>1}} - # class: Band - # embedded: false> - - Band.order_by(name: -1, description: 1) - # => #{"name"=>-1, "description"=>1}} - # class: Band - # embedded: false> - - Band.order_by(name: :desc, description: 'asc') - # => #{"name"=>-1, "description"=>1}} - # class: Band - # embedded: false> - -The direction may be specified as integers ``1`` and ``-1`` for ascending -and descending, respectively, or as symbols ``:asc`` and ``:desc``, or as -strings ``"asc"`` and ``"desc"``. - -Alternatively, ``order`` accepts an array of two-element arrays specifying -the ordering. Field names and directions may be strings or symbols. - -.. code-block:: ruby - - Band.order([['name', 'desc'], ['description', 'asc']]) - - Band.order([[:name, :desc], [:description, :asc]]) - -Another way of providing the order is to use ``#asc`` and ``#desc`` methods -on symbols, as follows: - -.. code-block:: ruby - - Band.order(:name.desc, :description.asc) - -The arguments can be provided as a string using SQL syntax: - -.. code-block:: ruby - - Band.order('name desc, description asc') - -Finally, there are ``asc`` and ``desc`` methods that can be used instead of -``order``/``order_by``: - -.. code-block:: ruby - - Band.asc('name').desc('description') - # => #{"name"=>1, "description"=>-1}} - class: Band - embedded: false> - -``order`` calls can be chained, in which case the oldest calls define the -most significant criteria and the newest calls define the least significant -ones (since in Ruby hashes maintain the order of their keys): - -.. code-block:: ruby - - Band.order('name desc').order('description asc') - # => #{"name"=>-1, "description"=>1}} - class: Band - embedded: false> - -This can sometimes lead to surprising results if there are scopes, including -the default scope, that use ``order``/``order_by``. For example, in the -following snippet bands are ordered by name first because the order in the -default scope takes precedence over the order given in the query, due to -the default scope being evaluated first: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :name, type: String - field :year, type: Integer - - default_scope -> { order(name: :asc) } - end - - Band.order(year: :desc) - # => #{"name"=>1, "year"=>-1}} - class: Band - embedded: false> - - -Pagination -========== - -Mongoid provides the pagination operators ``limit``, ``skip``, and ``batch_size`` on ``Criteria``. - -.. _limit: - -``limit`` ---------- - -``limit`` sets the total number of documents to be returned by a query: - -.. code-block:: ruby - - Band.limit(5) - # => - # #5} - # class: Band - # embedded: false> - -.. _skip: - -``skip`` --------- - -``skip`` (alias: ``offset``) sets the number of query results to skip -before returning documents. The ``limit`` value, if specified, will be applied -after documents are skipped. When performing pagination, ``skip`` is recommended -to be combined with :ref:`ordering ` to ensure consistent results. - -.. code-block:: ruby - - Band.skip(10) - # => - # #10} - # class: Band - # embedded: false> - -.. _batch-size: - -``batch_size`` --------------- - -When executing large queries, or when iterating over query results with an enumerator method such as -``Criteria#each``, Mongoid automatically uses the `MongoDB getMore command -`_ to load results in batches. -The default ``batch_size`` is 1000, however you may set it explicitly: - -.. code-block:: ruby - - Band.batch_size(500) - # => - # #500} - # class: Band - # embedded: false> - - -Finding By ``_id`` -================== - -Mongoid provides the ``find`` method on ``Criteria`` objects to find documents -by their ``_id`` values: - -.. code-block:: ruby - - Band.find('5f0e41d92c97a64a26aabd10') - # => # - -The ``find`` method performs type conversion, if necessary, of the argument -to the type declared in the model being queried for the ``_id`` field. -By default, the ``_id`` type is ``BSON::ObjectId``, thus the query above -is equivalent to: - -.. code-block:: ruby - - Band.find(BSON::ObjectId.from_string('5f0e41d92c97a64a26aabd10')) - # => # - -.. note:: - - When querying collections directly using the driver, type conversion is not - automatically performed: - -.. code-block:: ruby - - Band.collection.find(_id: BSON::ObjectId.from_string('5f0e41d92c97a64a26aabd10')).first - # => {"_id"=>BSON::ObjectId('5f0e41d92c97a64a26aabd10'), "name"=>"Juno Reactor"} - - Band.collection.find(_id: '5f0e41d92c97a64a26aabd10').first - # => nil - -The ``find`` method can accept multiple arguments, or an array of arguments. -In either case each of the arguments or array elements is taken to be an ``_id`` -value, and documents with all of the specified ``_id`` values are returned in -an array: - -.. code-block:: ruby - - Band.find('5f0e41d92c97a64a26aabd10', '5f0e41b02c97a64a26aabd0e') - # => [#, - #] - - Band.find(['5f0e41d92c97a64a26aabd10', '5f0e41b02c97a64a26aabd0e']) - # => [#, - #] - -If the same ``_id`` value is given more than once, the corresponding document -is only returned once: - -.. code-block:: ruby - - Band.find('5f0e41b02c97a64a26aabd0e', '5f0e41b02c97a64a26aabd0e') - # => [#] - -The documents returned are *not* ordered, and may be returned in a different -order from the order of provided ``_id`` values, as illustrated in the above -examples. - -If any of the ``_id`` values are not found in the database, the behavior of -``find`` depends on the value of the ``raise_not_found_error`` configuration -option. If the option is set to ``true``, ``find`` raises -``Mongoid::Errors::DocumentNotFound`` if any of the ``_id``\s are not found. -If the option is set to ``false`` and ``find`` is given a single ``_id`` to -find and there is no matching document, ``find`` returns ``nil``. If the -option is set to ``false`` and ``find`` is given an array of ids to find -and some are not found, the return value is an array of documents that were -found (which could be empty if no documents were found at all). - - -.. _additional-query-methods: - -Additional Query Methods -======================== - -Mongoid also has some helpful methods on criteria. - -.. list-table:: - :header-rows: 1 - :widths: 30 60 - - * - Operation - - Example - - * - ``Criteria#count`` - - *Get the total number of documents matching a filter, or the total - number of documents in a collection. Note this will always hit - the database for the count.* - - *As of Mongoid 7.2, the* ``count`` *method uses the* - ``count_documents`` *driver helper to obtain the accurate count. - previously the* ``count`` *driver helper was used which used - collection metadata and was thus not necessarily accurate (but - may have returned the result faster). Use* ``estimated_count`` - *method to obtain an approximate number of documents in the collection - quickly.* - - - - .. code-block:: ruby - - Band.count - Band.where(name: "Photek").count - - * - ``Criteria#estimated_count`` - - *Get an approximate number of documents in the collection using the - collection metadata. The* ``estimated_count`` *method does not accept - query conditions; if any are given, it will raise* - ``Mongoid::Errors::InvalidEstimatedCountCriteria``. - *If a model defines a default scope,* ``estimated_count`` *must be - called on the unscoped model*. - - - - .. code-block:: ruby - - Band.count - Band.where(name: "Photek").count - - class Contract - include Mongoid::Document - - field :active, type: Boolean - - default_scope -> { where(active: true) } - end - - Contract.estimated_count - # => raises Mongoid::Errors::InvalidEstimatedCountCriteria - - Contract.unscoped.estimated_count - # => 0 - - * - ``Criteria#distinct`` - - *Get a list of distinct values for a single field. Note this will always hit - the database for the distinct values.* - - *This method accepts the dot notation, thus permitting referencing - fields in embedded associations.* - - *This method respects :ref:`field aliases `, - including those defined in embedded documents.* - - - - .. code-block:: ruby - - Band.distinct(:name) - Band.where(:fans.gt => 100000). - distinct(:name) - - Band.distinct('cities.name') - - # Assuming an aliased field: - class Manager - include Mongoid::Document - embedded_in :band - field :name, as: :n - end - - # Expands out to "managers.name" in the query: - Band.distinct('managers.n') - - * - ``Criteria#each`` - - *Iterate over all matching documents in the criteria.* - - - - .. code-block:: ruby - - Band.where(members: 1).each do |band| - p band.name - end - - * - ``Criteria#exists?`` - - *Determine if any matching documents exist. Will return true if there - are 1 or more.* - - ``#exists?`` *now takes a number of argument types:* - - - ``Hash``: *A hash of conditions.* - - ``Object``: *An _id to search for.* - - ``false``/``nil``: *Always returns false.* - - - - .. code-block:: ruby - - Band.exists? - Band.where(name: "Photek").exists? - Band.exists?(name: "Photek") - Band.exists?(BSON::ObjectId('6320d96a3282a48cfce9e72c')) - Band.exists?('6320d96a3282a48cfce9e72c') - Band.exists?(false) - Band.exists?(nil) - - * - ``Criteria#fifth`` - - *Get the fifth document for the given criteria.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.fifth - - * - ``Criteria#fifth!`` - - *Get the fifth document for the given criteria, or raise an error if - none exist.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.fifth! - - * - ``Criteria#find_by`` - - *Find a document by the provided attributes. If not found, - raise an error or return nil depending on the value of the* - ``raise_not_found_error`` *configuration option.* - - - - .. code-block:: ruby - - Band.find_by(name: "Photek") - - Band.find_by(name: "Tool") do |band| - band.impressions += 1 - end - - * - ``Criteria#find_or_create_by`` - - *Find a document by the provided attributes, and if not found - create and return a newly persisted one. Note that attributes provided in the arguments to - this method will override any set in ``create_with``*. - - - - .. code-block:: ruby - - Band.find_or_create_by(name: "Photek") - Band.where(:likes.gt => 10).find_or_create_by(name: "Photek") - - ``find_or_create_by`` can be used on any scope, but in this case - the criteria given by the scope and by ``find_or_create_by`` are - combined. The following creates three bands: - - .. code-block:: ruby - - Band.find_or_create_by(name: "Photek") - Band.where(name: "Photek").find_or_create_by(name: "Aerosmith") - # creates Aerosmith again because there is no band whose name - # is Photek and Aerosmith at the same time - Band.where(name: "Photek").find_or_create_by(name: "Aerosmith") - - * - ``Criteria#find_or_initialize_by`` - - *Find a document by the provided attributes, and if not found - return a new one.* - - - - .. code-block:: ruby - - Band.find_or_initialize_by(name: "Photek") - Band.where(:likes.gt => 10).find_or_initialize_by(name: "Photek") - - * - ``Criteria#first|last`` - - *Finds a single document given the provided criteria. Get a list of - documents by passing in a limit argument. This method automatically adds - a sort on _id. This can cause performance issues, so if the sort is - undesirable, Criteria#take can be used instead.* - - - - .. code-block:: ruby - - Band.first - Band.where(:members.with_size => 3).first - Band.where(:members.with_size => 3).last - Band.first(2) - - * - ``Criteria#first!|last!`` - - *Finds a single document given the provided criteria, or raises an error - if none are found. This method automatically adds a sort on _id if no - sort is given. This can cause performance issues, so if the sort is - undesirable, Criteria#take! can be used instead.* - - - - .. code-block:: ruby - - Band.first! - Band.where(:members.with_size => 3).first! - Band.where(:members.with_size => 3).last! - - * - ``Criteria#first_or_create`` - - *Find the first document by the provided attributes, and if not found - create and return a newly persisted one.* - - - - .. code-block:: ruby - - Band.where(name: "Photek").first_or_create - - * - ``Criteria#first_or_create!`` - - *Find the first document by the provided attributes, and if not found - create and return a newly persisted one using* ``create!``. - - - - .. code-block:: ruby - - Band.where(name: "Photek").first_or_create! - - * - ``Criteria#first_or_initialize`` - - *Find the first document by the provided attributes, and if not found - return a new one.* - - - - .. code-block:: ruby - - Band.where(name: "Photek").first_or_initialize - - * - ``Criteria#for_js`` - - *Find documents for a provided JavaScript expression, optionally with - the specified variables added to the evaluation scope. The scope - argument is supported in MongoDB 4.2 and lower.* - *Prefer* :manual:`$expr ` *over* ``for_js``. - - - - .. code-block:: ruby - - # All MongoDB versions - Band.for_js("this.name = 'Tool'") - - # MongoDB 4.2 and lower - Band.for_js("this.name = param", param: "Tool") - - * - ``Criteria#fourth`` - - *Get the fourth document for the given criteria.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.fourth - - * - ``Criteria#fourth!`` - - *Get the fourth document for the given criteria, or raise an error if - none exist.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.fourth! - - * - ``Criteria#length|size`` - - *Same as count but caches subsequent calls to the database* - - - - .. code-block:: ruby - - Band.length - Band.where(name: "FKA Twigs").size - - * - ``Criteria#pick`` - - *Get the values from one document for the provided fields. - Returns nil for unset fields and for non-existent fields.* - - *This method does not apply a sort to the documents, so it - will not necessarily return the values from the first document.* - - *This method accepts the dot notation, thus permitting referencing - fields in embedded associations.* - - *This method respects :ref:`field aliases `, - including those defined in embedded documents.* - - - - .. code-block:: ruby - - Band.all.pick(:name) - - Band.all.pick('cities.name') - - # Using the earlier definition of Manager, - # expands out to "managers.name" in the query: - Band.all.pick('managers.n') - - - * - ``Criteria#pluck`` - - *Get all the values for the provided field. - Returns nil for unset fields and for non-existent fields.* - - *This method accepts the dot notation, thus permitting referencing - fields in embedded associations.* - - *This method respects :ref:`field aliases `, - including those defined in embedded documents.* - - - - .. code-block:: ruby - - Band.all.pluck(:name) - #=> ["Daft Punk", "Aphex Twin", "Ween"] - - Band.all.pluck('address.city') - #=> ["Paris", "Limerick", "New Hope"] - - # Using the earlier definition of Manager, - # expands out to "managers.name" in the query: - Band.all.pluck('managers.n') - #=> [ ["Berry Gordy", "Tommy Mottola"], [], ["Quincy Jones"] ] - - # Accepts multiple field arguments, in which case - # the result will be returned as an Array of Arrays. - Band.all.pluck(:name, :likes) - #=> [ ["Daft Punk", 342], ["Aphex Twin", 98], ["Ween", 227] ] - - * - ``Criteria#read`` - - *Sets the read preference for the criteria.* - - - - .. code-block:: ruby - - Band.all.read(mode: :primary) - - * - ``Criteria#second`` - - *Get the second document for the given criteria.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.second - - * - ``Criteria#second!`` - - *Get the second document for the given criteria, or raise an error if - none exist.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.second! - - * - ``Criteria#second_to_last`` - - *Get the second to last document for the given criteria.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.second_to_last - - * - ``Criteria#second_to_last!`` - - *Get the second to last document for the given criteria, or raise an - error if none exist.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.second_to_last! - - * - ``Criteria#take`` - - *Get a list of n documents from the database or just one if no parameter - is provided.* - - *This method does not apply a sort to the documents, so it can return - different document(s) than #first and #last.* - - - - .. code-block:: ruby - - Band.take - Band.take(5) - - * - ``Criteria#take!`` - - *Get a document from the database or raise an error if none exist.* - - *This method does not apply a sort to the documents, so it can return - different document(s) than #first and #last.* - - - - .. code-block:: ruby - - Band.take! - - * - ``Criteria#tally`` - - *Get a mapping of values to counts for the provided field.* - - *This method accepts the dot notation, thus permitting referencing - fields in embedded associations.* - - *This method respects :ref:`field aliases `, - including those defined in embedded documents.* - - - - .. code-block:: ruby - - Band.all.tally(:name) - - Band.all.tally('cities.name') - - # Using the earlier definition of Manager, - # expands out to "managers.name" in the query: - Band.all.tally('managers.n') - - * - ``Criteria#third`` - - *Get the third document for the given criteria.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.third - - * - ``Criteria#third!`` - - *Get the third document for the given criteria, or raise an error if - none exist.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.third! - - * - ``Criteria#third_to_last`` - - *Get the third to last document for the given criteria.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.third_to_last - - * - ``Criteria#third_to_last!`` - - *Get the third to last document for the given criteria, or raise an - error if none exist.* - - *This method automatically adds a sort on _id if no sort is given.* - - - - .. code-block:: ruby - - Band.third_to_last! - - -Eager Loading -============= - -Mongoid provides a facility to eager load documents -from associations to prevent the n+1 issue when -iterating over documents with association access. Eager loading is supported on -all associations with the exception of polymorphic ``belongs_to`` -associations. - -.. code-block:: ruby - - class Band - include Mongoid::Document - has_many :albums - end - - class Album - include Mongoid::Document - belongs_to :band - end - - Band.includes(:albums).each do |band| - p band.albums.first.name # Does not hit the database again. - end - - -Regular Expressions -=================== - -MongoDB, and Mongoid, allow querying documents by regular expressions. - -Given the following model definitions: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :name, type: String - field :description, type: String - end - - Band.create!(name: 'Sun Project', description: "Sun\nProject") - -... we can query using simple Ruby regular expressions in a natural way: - -.. code-block:: ruby - - Band.where(name: /project/i).first - # => # - -It is also possible to query using PCRE syntax by constructing -``BSON::Regexp::Raw`` objects explicitly: - -.. code-block:: ruby - - Band.where(description: /\AProject/).first - # => # - - Band.where(description: BSON::Regexp::Raw.new('^Project')).first - # => nil - - Band.where(description: BSON::Regexp::Raw.new('^Project', 'm')).first - # => # - - -Conditions On Fields -==================== - -When a condition uses a field defined in the model, the value being specified -in the condition is converted according to the rules of the field, if any. -For example, consider the following model definition that contains a ``Time`` -field, a ``Date`` field and an implicit ``Object`` field, and also -intentionally does not define a field called ``deregistered_at``: - -.. code-block:: ruby - - class Voter - include Mongoid::Document - - field :born_on, type: Date - field :registered_at, type: Time - field :voted_at - end - -Queries on ``born_on`` and ``registered_at`` fields using ``Date`` and ``Time`` -values, respectively, are straightforward: - -.. code-block:: ruby - - Voter.where(born_on: Date.today).selector - # => {"born_on"=>2020-12-18 00:00:00 UTC} - - Voter.where(registered_at: Time.now).selector - # => {"registered_at"=>2020-12-19 04:33:36.939788067 UTC} - -But, note the differences in behavior when providing a ``Date`` instance -in all possible scenarios: - -.. code-block:: ruby - - Voter.where(born_on: Date.today).selector - # => {"born_on"=>2020-12-18 00:00:00 UTC} - - Voter.where(registered_at: Date.today).selector - # => {"registered_at"=>2020-12-18 00:00:00 -0500} - - Voter.where(voted_at: Date.today).selector - # => {"voted_at"=>Fri, 18 Dec 2020} - - Voter.where(deregistered_at: Date.today).selector - # => {"deregistered_at"=>2020-12-18 00:00:00 UTC} - -When using the ``registered_at`` field which is of type ``Time``, the date -was interpreted to be in local time (as per the :ref:`configured time zone -`). When using the ``born_on`` field which is of type ``Date``, -the date was interpreted to be in UTC. When using the ``voted_at`` field -which was defined without a type (hence implicitly as an ``Object``), -the date was used unmodified in the constructed query. When using a -nonexistent field ``deregistered_at`` the date was interpreted to be in UTC -and converted to a time, matching the behavior of querying a ``Date`` field. - - -Scoping -======= - -Scopes provide a convenient way to reuse common criteria with more -business domain style syntax. - - -.. _named-scopes: - -Named Scopes ------------- - -Named scopes are simply criteria defined at class load that are referenced -by a provided name. Just like normal criteria, they are lazy and chainable. - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :country, type: String - field :genres, type: Array - - scope :english, ->{ where(country: "England") } - scope :rock, ->{ where(:genres.in => [ "rock" ]) } - end - - Band.english.rock # Get the English rock bands. - -Named scopes can take procs and blocks for accepting parameters or -extending functionality. - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :country, type: String - field :active, type: Boolean, default: true - - scope :named, ->(name){ where(name: name) } - scope :active, ->{ - where(active: true) do - def deutsch - tap do |scope| - scope.selector.store("origin" => "Deutschland") - end - end - end - } - end - - Band.named("Depeche Mode") # Find Depeche Mode. - Band.active.deutsch # Find active German bands. - -By default, Mongoid allows defining a scope that would shadow an existing -class method, as the following example shows: - -.. code-block:: ruby - - class Product - include Mongoid::Document - - def self.fresh - true - end - - scope :fresh, ->{ where(fresh: true) } - end - -To have Mongoid raise an error when a scope would overwrite an existing class -method, set the ``scope_overwrite_exception`` :ref:`configuration option -` to ``true``. - - -Default Scopes --------------- - -Default scopes can be useful when you find yourself applying the same -criteria to most queries, and wish to specify these criteria as the default. -Default scopes are procs that return criteria objects. - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :active, type: Boolean - - default_scope ->{ where(active: true) } - end - - Band.each do |band| - # All bands here are active. - end - -Specifying a default scope also initializes the fields of new models to -the values given in the default scope, if the values are simple literals: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :active, type: Boolean - field :num_tours, type: Integer - - default_scope ->{ where(active: true, num_tours: {'$gt' => 1}) } - end - - # active is set, num_tours is not set - Band.new # => # - -Note that if a default value is provided both in the field definition and -in the default scope, the value in the default scope takes precedence: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :active, type: Boolean, default: true - - default_scope ->{ where(active: false) } - end - - Band.new # => # - -Because a default scope initializes fields in new models as just described, -defining a default scope with a dotted key and a simple literal value, while -possible, is not recommended: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :tags, type: Hash - - default_scope ->{ where('tags.foo' => 'bar') } - end - - Band.create! - # => Created document: {"_id"=>BSON::ObjectId('632de48f3282a404bee1877b'), "tags.foo"=>"bar"} - Band.create!(tags: { 'foo' => 'bar' }) - # => Created document: {"_id"=>BSON::ObjectId('632de4ad3282a404bee1877c'), "tags.foo"=>"bar", "tags"=>{"foo"=>"bar"}} - Band.all.to_a - # => [ #"bar"}> ] - -Mongoid 8 allows dotted keys to be used in Mongoid, and when creating a document, -the scope is added as a dotted key in the attributes: - -.. code-block:: ruby - - Band.new.attribute - # => {"_id"=>BSON::ObjectId('632de97d3282a404bee1877d'), "tags.foo"=>"bar"} - -Whereas when querying, Mongoid looks for an embedded document: - -.. code-block:: ruby - - Band.create! - # => Created document: {"_id"=>BSON::ObjectId('632de48f3282a404bee1877b'), "tags.foo"=>"bar"} - Band.where - # => #"bar"} - options: {} - class: Band - embedded: false> - # This looks for something like: { tags: { "foo" => "bar" } } - Band.count - # => 0 - -A workaround is to define the default scope as a complex query: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :tags, type: Hash - - default_scope ->{ where('tags.foo' => {'$eq' => 'bar'}) } - end - - Band.create!(tags: { hello: 'world' }) - Band.create!(tags: { foo: 'bar' }) - # does not add a "tags.foo" dotted attribute - Band.count - # => 1 - -You can tell Mongoid not to apply the default scope by using -``unscoped``, which can be inline or take a block. - -.. code-block:: ruby - - Band.unscoped.where(name: "Depeche Mode") - Band.unscoped do - Band.where(name: "Depeche Mode") - end - -You can also tell Mongoid to explicitly apply the default scope -again later to always ensure it's there. - -.. code-block:: ruby - - Band.unscoped.where(name: "Depeche Mode").scoped - -If you are using a default scope on a model that is part of an association, -you must reload the association to have scoping reapplied. -This is important to note if you change a value of a document in the association -that would affect its visibility within the scoped association. - -.. code-block:: ruby - - class Label - include Mongoid::Document - embeds_many :bands - end - - class Band - include Mongoid::Document - field :active, default: true - embedded_in :label - default_scope ->{ where(active: true) } - end - - label.bands.push(band) - label.bands # [ band ] - band.update_attribute(:active, false) - label.bands # [ band ] Must reload. - label.reload.bands # [] - -.. note:: - - After the default scope is applied, it is no longer distinguished from - other query conditions. This can lead to surprising behavior when using - ``or`` and ``nor`` operators in particular: - - .. code-block:: ruby - - class Band - include Mongoid::Document - - field :name - field :active - field :touring - - default_scope ->{ where(active: true) } - end - - Band.where(name: 'Infected Mushroom') - # => - # #true, "name"=>"Infected Mushroom"} - # options: {} - # class: Band - # embedded: false> - - Band.where(name: 'Infected Mushroom').or(touring: true) - # => - # #[{"active"=>true, "name"=>"Infected Mushroom"}, {"touring"=>true}]} - # options: {} - # class: Band - # embedded: false> - - Band.or(touring: true) - # => - # #[{"active"=>true}, {"touring"=>true}]} - # options: {} - # class: Band - # embedded: false> - - In the last example, you might expect the two conditions - (``active: true`` and ``touring: true``) to be combined with an ``$and``, - but because the ``Band`` class already has the scope applied to it, - it becomes one of the disjunction branches of the ``or``. - - -Runtime Default Scope Override ------------------------------- - -You can use the ``with_scope`` method to change the default scope in a block -at runtime: - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :country, type: String - field :genres, type: Array - - scope :english, ->{ where(country: "England") } - end - - criteria = Band.with_scope(Band.english) do - Band.all - end - - criteria - # => - # #"England"} - # options: {} - # class: Band - # embedded: false> - -.. note:: - - If with_scope calls are nested, when the nested with_scope block completes - Mongoid 7 sets the current scope to nil instead of the parent scope. - Mongoid 8 will set the current scope to the correct parent scope. - To get Mongoid 8 behavior in Mongoid 7.4 and higher, set the - ``Mongoid.broken_scoping`` global option to false. - - -Class Methods -------------- - -Class methods on models that return criteria objects are also -treated like scopes, and can be chained as well. - -.. code-block:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :active, type: Boolean, default: true - - def self.active - where(active: true) - end - end - - Band.active - - -Queries + Persistence -===================== - -Mongoid supports persistence operations off of criteria -in a light capacity for when you want to expressively perform multi -document inserts, updates, and deletion. - -.. warning:: - - Criteria ordering and pagination conditions, including ``order``, ``limit``, - ``offset``, and ``batch_size``, will be ignored on the following operations. - -.. list-table:: - :header-rows: 1 - :widths: 30 60 - - * - Operation - - Example - - * - ``Criteria#create`` - - *Create a newly persisted document.* - - - - .. code-block:: ruby - - Band.where(name: "Photek").create - - * - ``Criteria#create!`` - - *Create a newly persisted document and raise an exception on validation failure.* - - - - .. code-block:: ruby - - Band.where(name: "Photek").create! - - * - ``Criteria#build|new`` - - *Create a new (unsaved) document.* - - - - .. code-block:: ruby - - Band.where(name: "Photek").build - Band.where(name: "Photek").new - - * - ``Criteria#update`` - - *Update attributes of the first matching document.* - - - - .. code-block:: ruby - - Band.where(name: "Photek").update(label: "Mute") - - * - ``Criteria#update_all`` - - *Update attributes of all matching documents.* - - - - .. code-block:: ruby - - Band.where(members: 2).update_all(label: "Mute") - - * - ``Criteria#add_to_set`` - - *Perform an $addToSet on all matching documents.* - - - - .. code-block:: ruby - - Band.where(name: "Photek").add_to_set(label: "Mute") - - * - ``Criteria#bit`` - - *Perform a $bit on all matching documents.* - - - - .. code-block:: ruby - - Band.where(name: "Photek").bit(likes: { and: 14, or: 4 }) - - * - ``Criteria#inc`` - - *Perform an $inc on all matching documents.* - - - - .. code-block:: ruby - - Band.where(name: "Photek").inc(likes: 123) - - * - ``Criteria#pop`` - - *Perform a $pop on all matching documents.* - - - - .. code-block:: ruby - - Band.where(name: "Photek").pop(members: -1) - Band.where(name: "Photek").pop(members: 1) - - * - ``Criteria#pull`` - - *Perform a $pull on all matching documents.* - - - - .. code-block:: ruby - - Band.where(name: "Tool").pull(members: "Maynard") - - * - ``Criteria#pull_all`` - - *Perform a $pullAll on all matching documents.* - - - - .. code-block:: ruby - - Band.where(name: "Tool"). - pull_all(:members, [ "Maynard", "Danny" ]) - - * - ``Criteria#push`` - - *Perform a $push on all matching documents.* - - - - .. code-block:: ruby - - Band.where(name: "Tool").push(members: "Maynard") - - * - ``Criteria#push_all`` - - *Perform a $push with $each on all matching documents.* - - - - .. code-block:: ruby - - Band.where(name: "Tool"). - push_all(members: [ "Maynard", "Danny" ]) - - * - ``Criteria#rename`` - - *Perform a $rename on all matching documents.* - - - - .. code-block:: ruby - - Band.where(name: "Tool").rename(name: :title) - - * - ``Criteria#set`` - - *Perform a $set on all matching documents.* - - - - .. code-block:: ruby - - Band.where(name: "Tool").set(likes: 10000) - - * - ``Criteria#unset`` - - *Perform a $unset on all matching documents.* - - - - .. code-block:: ruby - - Band.where(name: "Tool").unset(:likes) - - * - ``Criteria#delete`` - - *Deletes all matching documents in the database.* - - - - .. code-block:: ruby - - Band.where(label: "Mute").delete - - * - ``Criteria#destroy`` - - *Deletes all matching documents in the database while running callbacks for all. - This loads all documents into memory and can be an expensive operation.* - - - - .. code-block:: ruby - - Band.where(label: "Mute").destroy - - -.. _query-cache: - -Query Cache -=========== - -The Ruby MongoDB driver versions 2.14 and above provide query caching functionality. When enabled, the -query cache saves the results of previously executed find and aggregation -queries and reuses them in the future instead of performing the queries again, -thus increasing application performance and reducing database load. - -Please review the `driver query cache documentation -`_ -for details about the driver's query cache behavior. - -The rest of this section assumes that driver 2.14.0 or later is being used. - - -Enabling Query Cache --------------------- - -The query cache may be enabled by using the driver's namespace or Mongoid's -namespace. - - -.. _enabling-query-cache-automatically: - -Enabling Query Cache Automatically ----------------------------------- - -The MongoDB Ruby Driver provides middleware to automatically enable the query cache for -Rack web requests and ActiveJob job runs. Please see the :ref:`Query Cache Rack Middleware -` section on the configuration page for instructions. - -Note that the Query Cache Middleware does not apply to code executed outside web requests -and/or jobs. - - -.. _enabling-query-cache-manually: - -Enabling Query Cache Manually ------------------------------ - -To enable the Query Cache manually for a code segment, use: - -.. code-block:: ruby - - Mongo::QueryCache.cache do - # ... - end - -The Query Cache can also be explicitly enabled and disabled, although we -recommend to use the block form described above: - -.. code-block:: ruby - - begin - Mongo::QueryCache.enabled = true - # ... - ensure - Mongo::QueryCache.enabled = false - end - - -.. _query-cache-first-method: - -Caching the Result of ``#first`` --------------------------------- - -Calling the ``first`` method on a model class imposes an ascending sort by -the ``_id`` field on the underlying query. This may produce unexpected behavior -with query caching. - -For example, when calling ``all`` on a model class and then ``first``, -one would expect the second query to use the cached results from the first. -However, because of the sort imposed on the second query, both methods -will query the database and separately cache their results. - -.. code-block:: ruby - - Band.all.to_a - #=> Queries the database and caches the results - - Band.first - #=> Queries the database again because of the sort - -To use the cached results, call ``all.to_a.first`` on the model class. - - -.. _load-async: - -Asynchronous Queries -==================== - -Mongoid allows running database queries asynchronously in the background. -This can be beneficial when there is a need to get documents from different -collections. - -In order to schedule an asynchronous query call the ``load_async`` method on a -``Criteria``: - -.. code-block:: ruby - - class PagesController < ApplicationController - def index - @active_bands = Band.where(active: true).load_async - @best_events = Event.best.load_async - @public_articles = Article.where(public: true).load_async - end - end - -In the above example three queries will be scheduled for asynchronous execution. -Results of the queries can be later accessed as usual: - -.. code-block:: html - -
    - <%- @active_bands.each do -%> -
  • <%= band.name %>
  • - <%- end -%> -
- -Even if a query is scheduled for asynchronous execution, it might be executed -synchronously on the caller's thread. There are three possible scenarios depending -on when the query results are being accessed: - -#. If the scheduled asynchronous task has been already executed, the results are returned. -#. If the task has been started, but not finished yet, the caller's thread blocks until the task is finished. -#. If the task has not been started yet, it is removed from the execution queue, and the query is executed synchronously on the caller's thread. - -.. note:: - - Even though ``load_async`` method returns a ``Criteria`` object, you should not - do any operations on this object except accessing query results. The query is - scheduled for execution immediately after calling ``load_async``, therefore - later changes to the ``Criteria`` object may not be applied. - - -Configuring asynchronous query execution ----------------------------------------- - -Asynchronous queries are disabled by default. When asynchronous queries are -disabled, ``load_async`` will execute the query immediately on the current thread, -blocking as necessary. Therefore, calling ``load_async`` on criteria in this case -is roughly the equivalent of calling ``to_a`` to force query execution. - -In order to enable asynchronous query execution, the following config options -must be set: - -.. code-block:: yaml - - development: - ... - options: - # Execute asynchronous queries using a global thread pool. - async_query_executor: :global_thread_pool - # Number of threads in the pool. The default is 4. - # global_executor_concurrency: 4 diff --git a/docs/reference/rails-integration.txt b/docs/reference/rails-integration.txt deleted file mode 100644 index 0a43d96dca..0000000000 --- a/docs/reference/rails-integration.txt +++ /dev/null @@ -1,100 +0,0 @@ -.. _rails-integration: - -***************** -Rails Integration -***************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Mongoid seamlessly integrates into Ruby on Rails applications. -This page describes features that are automatically enabled in the context -of a Rails application and Rails-related functionality which can be -manually enabled. - - -Configuration -============= - -You can set Mongoid configuration options in your ``application.rb`` along with -other Rails environment specific options by accessing config.mongoid. The -``mongoid:config`` generator will create an initializer in -``config/initializers/mongoid.rb`` which can also be used for configuring -Mongoid. Note, though, that options set in your ``config/mongoid.yml`` will -take precedence over options set elsewhere; it is recommended that whenever -possible you use ``mongoid.yml`` as the default location for Mongoid -configuration. - -.. code-block:: ruby - - module MyApplication - class Application < Rails::Application - config.mongoid.logger = Logger.new(STDERR, :warn) - end - end - - -Model Preloading -================ - -In order to properly set up single collection inheritance, Mongoid needs to preload all -models before every request in development mode. This can get slow, so if you are not -using any inheritance it is recommended you turn this feature off. - -.. code-block:: ruby - - config.mongoid.preload_models = false - - -Exceptions -========== - -Similarly to ActiveRecord, Mongoid configures Rails to automatically convert -certain exceptions to well-known HTTP status codes, as follows: - -.. code-block:: ruby - - Mongoid::Errors::DocumentNotFound : 404 - Mongoid::Errors::Validations : 422 - - -Controller Runtime Instrumentation -================================== - -Mongoid provides time spent executing MongoDB commands (obtained via a -driver command monitoring subscription) to Rails' instrumentation event -``process_action.action_controller``. This time is logged together with view -time like so: - -.. code-block:: none - - Completed 200 OK in 2739ms (Views: 12.6ms | MongoDB: 0.2ms) - -This logging is set up automatically. - -Note: the time indicated is the time taken by MongoDB cluster to execute -MongoDB operations, plus the time taken to send commands and receive -results from MongoDB over the network. It does not include time taken by -the driver and Mongoid to generate the queries or type cast and otherwise -process the results. - -Rake Tasks -========== - -Mongoid provides the following rake tasks when used in a Rails environment: - -- ``db:create``: Exists only for dependency purposes, does not actually do anything. -- ``db:create_indexes``: Reads all index definitions from the models and attempts to create them in the database. -- ``db:remove_indexes``: Reads all secondary index definitions from the models. -- ``db:drop``: Drops all collections in the database with the exception of the system collections. -- ``db:migrate``: Exists only for dependency purposes, does not actually do anything. -- ``db:purge``: Deletes all data, including indexes, from the database. Since 3.1.0 -- ``db:schema:load``: Exists only for framework dependency purposes, does not actually do anything. -- ``db:seed``: Seeds the database from db/seeds.rb -- ``db:setup``: Creates indexes and seeds the database. -- ``db:test:prepare``: Exists only for framework dependency purposes, does not actually do anything. diff --git a/docs/reference/sessions.txt b/docs/reference/sessions.txt deleted file mode 100644 index 4faf35c078..0000000000 --- a/docs/reference/sessions.txt +++ /dev/null @@ -1,56 +0,0 @@ -.. _sessions: - -******** -Sessions -******** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -You can use sessions with Mongoid in a similar way that you would execute a transaction in ActiveRecord. -Namely, you can call a method, ``#with_session`` on a model class or on an instance of a model and execute -some operations in a block. All operations in the block will be executed in the context of single session. -Please see the MongoDB Ruby driver documentation for what session options are available. - -Please note the following limitations of sessions: - -- Sessions cannot be shared across threads; sessions are not thread-safe. This is consistent with the Ruby driver's support for sessions. - -- Sessions cannot be nested. You cannot called ``#with_session`` on a model class or a model instance within the block passed to the ``#with_session`` method on another model class or model instance. - -- All model classes and instances used within the session block must use the same driver client. For example, if you have specified different ``storage_options`` for another model used in the block than that of the model class or instance on which ``#with_session`` is called, you will get an error. - -Using a Session via Model#with_session -====================================== - -Call ``#with_session`` on a model class and pass it session options to execute a block in the context -of a session. - -.. code-block:: ruby - - Person.with_session(causal_consistency: true) do - Person.create! - person = Person.first - person.name = "Emily" - person.save - end - - -Using a Session via model#with_session -====================================== - -Call ``#with_session`` on a model instance and pass it session options to execute a block in the context -of a session. - -.. code-block:: ruby - - person.with_session(causal_consistency: true) do - person.username = 'Emily' - person.save - person.posts << Post.create! - end diff --git a/docs/reference/sharding.txt b/docs/reference/sharding.txt deleted file mode 100644 index 6fd4152260..0000000000 --- a/docs/reference/sharding.txt +++ /dev/null @@ -1,146 +0,0 @@ -.. _sharding: - -********************** -Sharding Configuration -********************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -Mongoid can assist with setting up collection sharding in sharded environments. - - -.. _shard-keys: - -Declaring Shard Keys -==================== - -Shard keys can be declared on models using the ``shard_key`` macro: - -.. code-block:: ruby - - class Person - include Mongoid::Document - - field :ssn - - shard_key ssn: 1 - - # The collection must also have an index that starts with the shard key. - index ssn: 1 - end - -Note that in order to shard a collection, the collection must have an index -that starts with the shard key. Mongoid provides :ref:`index management -` functionality, which the examples here take -advantage of. - -Mongoid supports two syntaxes for declaring shard keys. The standard syntax -follows the format of MongoDB `shardCollection shell helper -`_ -and allows specifying ranged and hashed shard keys, compound shard keys and -collection sharding options: - -.. code-block:: ruby - - shard_key ssn: 1 - - shard_key ssn: 1, country: 1 - - shard_key ssn: :hashed - - shard_key {ssn: :hashed}, unique: true - -The alternative is the shorthand syntax, in which only the keys are given. -This syntax only supports ranged shard keys and does not allow options to -be specified: - -.. code-block:: ruby - - shard_key :ssn - - shard_key :ssn, :country - -``shard_key`` macro can take the name of a ``belongs_to`` association in -place of a field name, in which case Mongoid will use the foreign key -configured in the association as the field name: - -.. code-block:: ruby - - class Person - include Mongoid::Document - - belongs_to :country - - # Shards by country_id. - shard_key country: 1 - - # The collection must also have an index that starts with the shard key. - index country: 1 - end - -The shard key may also reference a field in an embedded document, by using -the "." character to delimit the field names: - -.. code-block:: ruby - - shard_key "location.x" => 1, "location.y" => 1 - - shard_key "location.x", "location.y" - -.. note:: - - Because the "." character is used to delimit fields in embedded documents, - Mongoid does not currently support shard key fields that themselves - literally contain the "." character. - -.. note:: - - If a model declares a shard key, Mongoid expects the respective collection - to be sharded with the specified shard key. When reloading models, Mongoid - will provide the shard key in addition to the ``id`` field value to the - ``find`` command to improve query performance, especially on `geographically - distributed sharded clusters `_. - If the collection is not sharded with the specified shard key, queries - may produce incorrect results. - - -.. _sharding-management: - -Sharding Management Rake Tasks -============================== - -To shard collections in the database according to the shard keys defined in -the models, run the ``db:mongoid:shard_collections`` Rake task. -If necessary, run the ``db:mongoid:create_indexes`` Rake task prior to -sharding collections: - -.. code-block:: bash - - rake db:mongoid:create_indexes - rake db:mongoid:shard_collections - -.. note:: - - Like with index management rake tasks, sharding management rake tasks - generally do not stop and fail when they encounter the problem with a - particular model class. Instead they log the problem (to the configured - Mongoid logger) at an appropriate level and continue with the next model. - When Mongoid is used in a Rails application, this means the results of - the rake task execution will generally be found in the per-environment - log file like ``log/development.log``. - -.. note:: - - When performing schema-related operations in a sharded cluster, such as - sharding collections as described in this document, or creating or dropping - collections or databases, cluster nodes may end up with out of date local - configuration-related cache data. Execute the `flushRouterConfig - `_ - command on each ``mongos`` node to clear these caches. diff --git a/docs/reference/text-search.txt b/docs/reference/text-search.txt deleted file mode 100644 index b7c3013de6..0000000000 --- a/docs/reference/text-search.txt +++ /dev/null @@ -1,84 +0,0 @@ -.. _text-search: - -*********** -Text Search -*********** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -MongoDB provides :manual:`text indexes ` -to support text search queries on string content. Text indexes -can include any field whose value is a string or an array of -string elements. - -.. note:: - - MongoDB Atlas also provides - `Atlas Search `_ - which is a more powerful and flexible text search solution. - The rest of this section discusses text indexes and not Atlas Search. - -To perform text search with Mongoid, follow these steps: - -1. Define a text index on a model. -2. Create the text index on the server. -3. Build a text search query. - - -Defining Text Search Index --------------------------- - -Index definition through Mongoid is described in detail on the :ref:`indexes -` page. Text search indexes are described in detail -under `text indexes `_ -in the MongoDB manual. Below is an example definition of a Band model with -a text index utilizing the description field: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :name, type: String - field :description, type: String - - index description: 'text' - end - -Note that the index type (``text``) must be given as a string, not as a symbol. - - -Creating Text Index -------------------- - -To create the index, invoke the ``db:mongoid:create_indexes`` Rake task: - -.. code-block:: ruby - - bundle exec rake db:mongoid:create_indexes - - -Querying Using Text Index -------------------------- - -To find bands whose description contains "ounces" or its variations, use the -`$text operator `_: - -.. code-block:: ruby - - Band.where('$text' => {'$search' => 'ounces'}).to_a - # => [#] - -Note that the description contains the word "ounce" even though the search -query was "ounces". - -Note also that when performing text search, the name of the field is not -explicitly specified - ``$text`` operator searches all fields indexed with -the text index. diff --git a/docs/reference/transactions.txt b/docs/reference/transactions.txt deleted file mode 100644 index ecf2465ea1..0000000000 --- a/docs/reference/transactions.txt +++ /dev/null @@ -1,232 +0,0 @@ -.. _transactions: - -************ -Transactions -************ - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Version 4.0 of the MongoDB server introduces -`multi-document transactions `_. -(Updates to multiple fields within a single document are atomic in all -versions of MongoDB). Transactions require a non-standalone MongoDB topology -and Ruby driver version 2.6 or higher. A higher level transaction API requires -Mongoid version 9.0 or higher, while a lower level API requires Mongoid -version 6.4 or higher. - -Using Transactions -================== - -Higher Level API ----------------- - -A transaction can be started by calling the ``transaction`` method on an instance -of a Mongoid document class, on a Mongoid document class, on or ``Mongoid`` module: - -.. code-block:: ruby - - Band.transaction do - Band.create(title: 'Led Zeppelin') - end - - band = Band.create(title: 'Deep Purple') - band.transaction do - band.active = false - band.save! - end - - Mongoid.transaction do - band.destroy - end - -When the ``transaction`` method is called, Mongoid does the following: - -* creates a session on a client that is used by the receiver of the - ``transaction`` method call; -* starts a transaction on the session; -* executes the given block; -* commits the transaction if no exception raised in the block; - - * calls ``after_commit`` callbacks for all objects modified inside the transaction -* aborts the transaction if an exception is raised in the block; - - * calls ``after_rollback`` callbacks for all objects modified inside the transaction -* closes the session - -.. note:: - - Since a transaction is tied to a particular client, _only_ operations on - the same client will be in scope of the transaction. Therefore it - is recommended that only objects that use the same client are used inside the - ``transaction`` method block. - - .. code-block:: ruby - - class Author - include Mongoid::Document - store_in client: :encrypted_client - end - - class User - include Mongoid::Document - store_in client: :encrypted_client - end - - class Article - include Mongoid::Document - # This class uses the :default client - end - - # Transaction is started on the :encrypted_client - Author.transaction do - # This operation uses the same client, so it is in the transaction - Author.create! - # This operation also uses the same client, so it is in the transaction - User.create! - # This operation uses a different client, so it is NOT in the transaction - Article.create! - end - -.. note:: - When ``transaction`` method is called on ``Mongoid`` module, the transaction - is created using the ``:default`` client. - -Aborting Transaction -~~~~~~~~~~~~~~~~~~~~ - -Any exception raised inside the ``transaction`` method block aborts the -transaction. Normally the raised exception passed on, except for the -``Mongoid::Errors::Rollback``. This error should be raised if you want to -explicitly abort the transaction without passing on an exception. - -Callbacks -~~~~~~~~~ - -Transaction API introduces two new callbacks - ``after_commit`` and ``after_rollback``. - -``after_commit`` callback is triggered for an object that was created, saved, -or destroyed: - -* after transaction is committed if the object was modified inside the transaction; -* after the object was persisted if the object was modified outside a transaction. - -.. note:: - In any case ``after_commit`` callback is triggered only after all other callbacks - were executed successfully. Therefore, if the object is modified without a - transaction, it is possible that the object was persisted, but ``after_commit`` - callback was not triggered (for example, an exception raised in ``after_save`` - callback). - -``after_rollback`` callback is triggered for an object that was created, saved, -or destroyed inside a transaction if the transaction was aborted. ``after_rollback`` -is never triggered without a transaction. - - -Lower Level API ---------------- - -In order to start a transaction, the application must have a :ref:`session `. - -A transaction can be started by calling the ``start_transaction`` method on a session, which can be -obtained by calling the ``with_session`` method on either a model class or instance: - -.. code-block:: ruby - - class Person - include Mongoid::Document - end - - Person.with_session do |session| - session.start_transaction - end - - person = Person.new - person.with_session do |session| - session.start_transaction - end - -It is also possible to specify read concern, write concern and read preference -when starting a transaction: - -.. code-block:: ruby - - Person.with_session do |session| - session.start_transaction( - read_concern: {level: :majority}, - write_concern: {w: 3}, - read: {mode: :primary}) - end - -A transaction may be committed or aborted. The corresponding methods to do so are -``commit_transaction`` and ``abort_transaction``, again on the session instance: - -.. code-block:: ruby - - Person.with_session do |session| - session.commit_transaction - end - - Person.with_session do |session| - session.abort_transaction - end - -If a session ends with an open transaction, -`the transaction is aborted `_. - -The transaction commit `can be retried `_ -if it fails. Here is the Ruby code to do so: - -.. code-block:: ruby - - begin - session.commit_transaction - rescue Mongo::Error => e - if e.label?(Mongo::Error::UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL) - retry - else - raise - end - end - -Note that in order to perform operations within the transaction, operations must use the same client -that the session was initiated on. By default, all operations will be done on the default client: - -.. code-block:: ruby - - class Person - include Mongoid::Document - end - - class Post - include Mongoid::Document - end - - Person.with_session do |s| - s.start_transaction - Person.create! - Person.create! - Post.create! - s.commit_transaction - end - -To explicitly use a different client, use the ``with`` method: - -.. code-block:: ruby - - Post.with(client: :other) do - Person.with(client: :other) do - Person.with_session do |s| - s.start_transaction - Person.create! - Person.create! - Post.create! - s.commit_transaction - end - end - end diff --git a/docs/reference/validation.txt b/docs/reference/validation.txt deleted file mode 100644 index a855c00652..0000000000 --- a/docs/reference/validation.txt +++ /dev/null @@ -1,66 +0,0 @@ -.. _validation: - -********** -Validation -********** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Mongoid includes ``ActiveModel::Validations`` to supply the basic -validation plus an additional associated and uniqueness validator. - -See the `Active Record Validations -`_ -Rails guide and `ActiveModel::Validations -`_ -documentation for more information. - -Mongoid behaves slightly differently to Active Record when using ``#valid?`` -on already persisted data. Active Record's ``#valid?`` will run all -validations whereas Mongoid's ``#valid?`` will only run validations on -documents that are in memory as an optimization. - - -``validates_uniqueness_of`` and ``:conditions`` Option -======================================================= - -The ``:conditions`` option to ``validates_uniqueness_of`` can be used to -provide additional conditions to add to the database query looking for -identical documents. This option does not influence when the validation -is executed because it is not considered when Mongoid retrieves the present -value of the respective field from the model. Consider the following example: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :name, type: String - field :year, type: Integer - - validates_uniqueness_of :name, conditions: -> { where(:year.gte => 2000) } - end - - # OK - Band.create!(name: "Sun Project", year: 2000) - - # Fails validation because there is a band with the "Sun Project" name - # and year 2000 in the database, even though the model being created now - # does not have a year. - Band.create!(name: "Sun Project") - - -Read preference with ``validates_uniqueness_of`` -================================================ - -In order to validate the uniqueness of an attribute, Mongoid must check that -the value for that attribute does not already exist in the database. If Mongoid -queries a secondary member of the replica set, there is a possibility that it -is reading stale data. Because of this, the queries used to check a -``validates_uniqueness_of`` validation always use read preference ``primary``. diff --git a/docs/release-notes.txt b/docs/release-notes.txt deleted file mode 100644 index 271271030d..0000000000 --- a/docs/release-notes.txt +++ /dev/null @@ -1,31 +0,0 @@ -.. _release-notes: - -************* -Release Notes -************* - -.. default-domain:: mongodb - -.. toctree:: - :titlesonly: - - release-notes/upgrading - release-notes/mongoid-9.0 - release-notes/mongoid-8.1 - release-notes/mongoid-8.0 - release-notes/mongoid-7.5 - release-notes/mongoid-7.4 - release-notes/mongoid-7.3 - -Overview --------- - -See the following sections to learn more about upgrading Mongoid: - -- :ref:`Upgrading Mongoid ` -- :ref:`Mongoid 9.0 ` -- :ref:`Mongoid 8.1 ` -- :ref:`Mongoid 8.0 ` -- :ref:`Mongoid 7.5 ` -- :ref:`Mongoid 7.4 ` -- :ref:`Mongoid 7.3 ` \ No newline at end of file diff --git a/docs/release-notes/mongoid-7.3.txt b/docs/release-notes/mongoid-7.3.txt deleted file mode 100644 index 6e6f58687c..0000000000 --- a/docs/release-notes/mongoid-7.3.txt +++ /dev/null @@ -1,310 +0,0 @@ -.. _mongoid-7.3: - -*********** -Mongoid 7.3 -*********** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -This page describes significant changes and improvements in Mongoid 7.3. -The complete list of releases is available `on GitHub -`_ and `in JIRA -`_; -please consult GitHub releases for detailed release notes and JIRA for -the complete list of issues fixed in each release, including bug fixes. - - -``delete`` Method Does Not Trigger Association Dependent Behavior ----------------------------------------------------------------------- - -**Breaking change:** In Mongoid 7.3, -:ref:`dependent behavior ` is not invoked -when the parent association is deleted using the ``delete`` method. -For example, after the following code snippet executes, in Mongoid 7.3 the -album will remain in the database: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_many :albums, dependent: :destroy - end - - class Album - include Mongoid::Document - - belongs_to :band - end - - band = Band.create! - album = Album.create!(band: band) - - # Does not delete the album from the database - band.delete - -Previous versions of Mongoid invoked dependent behavior when deleting parents. - -To invoke dependent behavior, use the ``destroy`` method: - -.. code-block:: ruby - - # Deletes the album from the database - band.destroy - -The behavior of Mongoid 7.3 is consistent with how ActiveRecord behaves. - - -``::Boolean`` Removed ---------------------- - -**Breaking change:** Mongoid 7.3 removes the global ``::Boolean`` class. - -This change should have no impact on classes that simply use ``Boolean`` -fields, as the ``Boolean`` class is aliased from ``Mongoid::Fields`` -(which is included in ``Mongoid::Document``). The following field definition -continues to work in 7.3 as it did in 7.2: - -.. code-block:: ruby - - class User - include Mongoid::Document - - field :verified, type: Boolean - end - -However, code that is not executed in the context of a class including -``Mongoid::Document`` may need to explicitly qualify ``Boolean`` references. -The following snippet fails with Mongoid 7.3 due to ``Boolean`` being -unqualified: - -.. code-block:: ruby - - class User - include Mongoid::Document - end - - User.field :verified, type: Boolean - -To fix it, use the fully-qualified ``Mongoid::Boolean`` class: - -.. code-block:: ruby - - User.field :verified, type: Mongoid::Boolean - -Note that ``class_eval`` is executed in the scope of the caller, not in -the scope of the class being modified. Thus even when using ``class_eval`` -it is necessary to fully qualify ``Mongoid::Boolean``: - -.. code-block:: ruby - - User.class_eval do - field :verified, type: Mongoid::Boolean - end - -Additionally, in Mongoid 7.2 ``::Boolean`` and ``Mongoid::Boolean`` were -different classes. In Mongoid 7.3 there is only one class which is -``Mongoid::Boolean``. - -It is possible to restore the global ``::Boolean`` class by executing in -your application: - -.. code-block:: ruby - - Boolean = Mongoid::Boolean - -Note that this aliases ``Mongoid::Boolean`` to ``::Boolean`` such that there -is still only a single Boolean class: - -.. code-block:: ruby - - # With Mongoid 7.3: - Boolean = Mongoid::Boolean - Boolean == Mongoid::Boolean - # => true - - # With Mongoid 7.2: - Boolean == Mongoid::Boolean - # => false - - -Selector Key Stringification ----------------------------- - -Minor change: Mongoid now converts symbol keys to string keys in the -``Criteria`` selectors. This applies to operators as well as hash literals. - -Mongoid 7.3 behavior: - -.. code-block:: ruby - - Band.and(year: {'$in': [2020]}) - # => - # #{"$in"=>[2020]}} - # options: {} - # class: Band - # embedded: false> - - Band.where(tag: {city: 1}) - # => - # #{"city"=>1}} - # options: {} - # class: Band - # embedded: false> - -Mongoid 7.2 behavior: - -.. code-block:: ruby - - Band.and(year: {'$in': [2020]}) - # => - # #{:$in=>[2020]}} - # options: {} - # class: Band - # embedded: false> - - Band.where(tag: {city: 1}) - # => - # #{:city=>1}} - # options: {} - # class: Band - # embedded: false> - - -Condition Combination Using ``$eq`` / ``$regex`` ------------------------------------------------- - -Minor change: when using the ``where``, ``and``, ``or``, and ``nor`` methods -on ``Criteria`` objects and providing multiple conditions on the same field -in the same argument using the symbol operator syntax, conditions may be -combined using ``$eq`` or ``$regex`` operators, as appropriate, instead of -``$and``. - -Mongoid 7.3 behavior: - -.. code-block:: ruby - - Band.where(year: 2020, :year.gt => 1960) - # => - # #{"$eq"=>2020, "$gt"=>1960}} - # options: {} - # class: Band - # embedded: false> - - Band.where(name: /A/, :name.ne => 'Astral') - # => - # #{"$regex"=>/A/, "$ne"=>"Astral"}} - # options: {} - # class: Band - # embedded: false> - -Mongoid 7.2 behavior: - -.. code-block:: ruby - - Band.where(year: 2020, :year.gt => 1960) - # => - # #2020, "$and"=>[{"year"=>{"$gt"=>1960}}]} - # options: {} - # class: Band - # embedded: false> - - Band.where(name: /A/, :name.ne => 'Astral') - # => - # #/A/, "$and"=>[{"name"=>{"$ne"=>"Astral"}}]} - # options: {} - # class: Band - # embedded: false> - -The ``$regex`` operator is used when the value is a regular expression, i.e. -an instance of ``Regexp`` or ``BSON::Regexp::Raw`` classes. - -When using the ``not`` method with multiple conditions provided in the same -argument, the conditions are kept together and negated as a group. - -Mongoid 7.3 behavior: - -.. code-block:: ruby - - Band.not(year: 2020, :year.gt => 1960) - # => - # #[{"$nor"=>[{"year"=>{"$eq"=>2020, "$gt"=>1960}}]}]} - # options: {} - # class: Band - # embedded: false> - -Mongoid 7.2 behavior: - -.. code-block:: ruby - - Band.not(year: 2020, :year.gt => 1960) - # => - # #{"$ne"=>2020}, "$and"=>[{"$nor"=>[{"year"=>{"$gt"=>1960}}]}]} - # options: {} - # class: Band - # embedded: false> - - -New Embedded Matching Operators -------------------------------- - -Mongoid 7.3 adds support for bitwise operators, ``$comment``, ``$mod`` and -``$type`` operators when :ref:`embedded matching `. - - -Unaliasing ``id`` Field ------------------------ - -It is now possible to :ref:`remove the id alias in models `, -to make ``id`` a regular field. - - -``Mongoid.purge!`` and ``Mongoid.truncate`` take the global overrides into account ----------------------------------------------------------------------------------- - -Minor change: ``Mongoid.purge!`` and ``Mongoid.truncate!`` now consider global -overrides set with ``Mongoid.override_database`` and ``Mongoid.override_client``. - -Mongoid 7.3 behavior: - -.. code-block:: ruby - - Mongoid.override_database("some_other_db") - Band.create!(name: "Garage") - Band.count # => 1 - Mongoid.purge! # or Mongoid.truncate! - Band.count # => 0 - -Mongoid 7.2 behavior: - -.. code-block:: ruby - - Mongoid.override_database("some_other_db") - Band.create!(name: "Garage") - Band.count # => 1 - Mongoid.purge! # or Mongoid.truncate! - Band.count # => 1 - - -``update_one`` Warnings in ``upsert`` -------------------------------------- - -Mongoid 7.3.5 fixes incorrect usage of the driver's ``update_one`` method from -Mongoid's ``upsert`` method. Mongoid's ``upsert`` actually performs a -replacing upsert, and Mongoid 7.3.5 and later correctly call ``replace_one``. diff --git a/docs/release-notes/mongoid-7.4.txt b/docs/release-notes/mongoid-7.4.txt deleted file mode 100644 index dd3af5e7f5..0000000000 --- a/docs/release-notes/mongoid-7.4.txt +++ /dev/null @@ -1,584 +0,0 @@ -.. _mongoid-7.4: - -*********** -Mongoid 7.4 -*********** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -This page describes significant changes and improvements in Mongoid 7.4. -The complete list of releases is available `on GitHub -`_ and `in JIRA -`_; -please consult GitHub releases for detailed release notes and JIRA for -the complete list of issues fixed in each release, including bug fixes. - -All behavior changes in Mongoid 7.4 must be explicitly requested by changing -the value of configuration options as detailed below. By default, -Mongoid 7.4 behaves the same as Mongoid 7.3. - - -Ruby Version Support --------------------- - -As of version 7.4, Mongoid supports Ruby 2.5+. -Support for Ruby 2.4 and earlier has been dropped. - - -Support for MongoDB 3.4 and Earlier Servers Deprecated ------------------------------------------------------- - -Mongoid 7.4 deprecates support for MongoDB 3.4 and earlier. -Mongoid 8 will require MongoDB 3.6 or newer. - - -Feature Flags Summary ---------------------- - -To ensure a stable upgrade path from Mongoid 7.3, Mongoid 7.4 -introduces feature flags which are further explained in the -sections below. - -To enable all new behavior in Mongoid 7.4, please use the following -:ref:`configuration options ` in your mongoid.yml file. -We recommend newly created apps to do this as well. - -.. code-block:: yaml - - development: - ... - options: - # Enable all new behavior in Mongoid 7.4 - legacy_triple_equals: false - object_id_as_json_oid: false - compare_time_by_ms: true - broken_aggregables: false - broken_updates: false - broken_and: false - broken_scoping: false - broken_alias_handling: false - legacy_pluck_distinct: false - - -Change ``===`` Operator To Match Ruby Semantics ------------------------------------------------ - -In Mongoid 7.4, the ``===`` operator on ``Mongoid::Document`` classes and -instances can be configured to behave the same way as it does in Ruby, -and is equivalent to calling ``is_a?`` on the right hand -side with the left hand side as the argument: - -.. code-block:: ruby - - ModelClass === instance - - # equivalent to: - instance.is_a?(ModelClass) - -In order to get this functionality, the ``Mongoid.legacy_triple_equals`` -option must be set to false. If it is set to true, which is the default for -Mongoid 7.4, the ``===`` operator will function as it did in Mongoid 7.3: -``===`` returned ``true`` for some cases when the equivalent Ruby -``===`` implementation returned false, as per the examples below. - -Mongoid 7.4 with ``Mongoid.legacy_triple_equals`` set to ``false`` behavior: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - has_many :members - end - - class CoverBand < Band - end - - class Member - include Mongoid::Document - - belongs_to :band - end - - band = Band.new - cover_band = CoverBand.new - - band === Band - # => false - - cover_band === Band - # => false - - Band === Band - # => false - - CoverBand === Band - # => false - - band.members === Array - # => false - - band.members === Mongoid::Association::Referenced::HasMany::Enumerable - # => false - -Mongoid 7.3 and 7.4 with ``Mongoid.legacy_triple_equals`` set to ``true`` -behavior: - -.. code-block:: ruby - - band === Band - # => true - - cover_band === Band - # => true - - Band === Band - # => true - - CoverBand === Band - # => true - - band.members === Array - # => true - - band.members === Mongoid::Association::Referenced::HasMany::Enumerable - # => true - -The standard invocation of ``===``, that is having the class on the left and -the instance on the right, works the same in Mongoid 7.4 as it did previously -and matches the core Ruby behavior: - -.. code-block:: ruby - - Band === band - # => true - - Band === cover_band - # => true - -.. note:: - - In Mongoid 8.0, the default value of the ``Mongoid.legacy_triple_equals`` option will - change to ``false``. - - -Return String ``_id`` Value (Hexadecimal) from ``BSON::ObjectId#as_json`` -------------------------------------------------------------------------- - -Mongoid 7.4 permits configuring the ``BSON::ObjectId#as_json`` method -to return the ``_id`` value as a hexadecimal string instead of the -``{"$oid" => "..."}`` hash it has returned in Mongoid 7.3 and previous -versions. - -When ``Mongoid.object_id_as_json_oid`` is set to ``false``, Mongoid will -delegate to ``bson-ruby`` implementation of ``BSON::ObjectId#as_json``. -In ``bson-ruby`` 4 the ``BSON::ObjectId#as_json`` method will continue -to return the hash ``{"$oid" => "..."}`` for backwards compatibility, but -in ``bson-ruby`` 5 the ``BSON::ObjectId#as_json`` method will return only -the hexadecimal ObjectId string. - -When ``Mongoid.object_id_as_json_oid`` is set to ``true``, Mongoid will -install an implementation of ``BSON::ObjectId#as_json`` which returns -the hash ``{"$oid" => "..."}`` as it did in Mongoid 7.3 and earlier. - -The behavior of ``as_json`` is summarized in the following table: - -.. list-table:: - :header-rows: 1 - :stub-columns: 1 - :class: compatibility-large no-padding - - * - ``Mongoid.object_id_as_json_oid`` value - - true - - false - - * - ``bson-ruby`` 4 - - ``{"$oid"=>"621ed7fda15d5d231594627c"}`` - - ``{"$oid"=>"621ed7fda15d5d231594627c"}`` - - * - ``bson-ruby`` 5 - - ``{"$oid"=>"621ed7fda15d5d231594627c"}`` - - ``"621ed7fda15d5d231594627c"`` - -.. note:: - - In Mongoid 8.0, the default value of the ``Mongoid.object_id_as_json_oid`` option will - change to ``false``. - - -Scoped Associations -------------------- - -Associations now support the ``:scope`` argument, yielding -:ref:`scoped associations `. - - -Compare Times With Millisecond Precision When Embedded Matching ---------------------------------------------------------------- - -Mongoid 7.4 with the ``Mongoid.compare_time_by_ms`` option set to ``true`` -will truncate the times to millisecond precision when comparing them while -performing embedded matching. - -Time objects in Ruby have nanosecond precision, whereas MongoDB server -can only store times with millisecond precision. Set the -``Mongoid.compare_time_by_ms`` option to ``true`` to truncate times to -millisecond precision when performing queries on already loaded embedded -associations (this is also called "embedded matching" and is done completely -in Ruby), to obtain the same query results when performing time comparisons -regardless of which documents are being queried. Setting this option to -``false`` will produce different results for queries on embedded associations -that are already loaded into memory vs queries on unloaded associations and -top-level models. - -The ``Mongoid.compare_time_by_ms`` option is set to ``false`` by default -in Mongoid 7.4 for backwards compatibility. - -.. note:: - - In Mongoid 8.0, the default value of the ``Mongoid.compare_time_by_ms`` option will - change to ``true``. - - -``count``, ``sum``, ``avg``, ``min``, ``max`` Ignore Sort If Not Limiting/Skipping ----------------------------------------------------------------------------------- - -The ``count``, ``sum``, ``avg``, ``min`` and ``max`` methods now omit the -sort stage from the generated aggregation pipeline if no skip or limit -is specified, because the results aren't affected by the sort order. -Example call that will now omit the sort stage and would potentially use -an index where it wouldn't before: - -.. code-block:: ruby - - Band.desc(:name).count - - -Return ``0`` When Aggregating Empty Result Sets ------------------------------------------------ - -Mongoid 7.4 with the ``Mongoid.broken_aggregables`` option set to ``false`` -will return ``0`` from the ``sum`` method over an empty result set, for example: - -.. code-block:: ruby - - Product.where(impossible_condition: true).sum(:price) - # => 0 - -Mongoid 7.3 and Mongoid 7.4 with the ``Mongoid.broken_aggregables`` option -set to ``true`` (the default) returns ``nil`` in this case. - -.. note:: - - In Mongoid 8.0, the default value of the ``Mongoid.broken_aggregables`` option will - change to ``false``. - - -Correct Update Behavior When Replacing Association --------------------------------------------------- - -Mongoid 7.4 with the ``Mongoid.broken_updates`` option set to ``false`` -will correctly persist an ``embeds_one`` association target that is set to nil -and then to a non-nil value, for example: - -.. code-block:: ruby - - class Canvas - include Mongoid::Document - - embeds_one :palette - end - - canvas.palette = palette - canvas.palette = nil - canvas.palette = palette - -In Mongoid 7.3 and earlier, and in 7.4 with the ``Mongoid.broken_aggregables`` -option set to ``true`` (the default), ``canvas.palette`` would be ``nil`` when -we would expect it to be ``palette``. - -.. note:: - - In Mongoid 8.0, the default value of the ``Mongoid.broken_updates`` option will - change to ``false`` - - -Correct Logical ``and`` Query Generation ----------------------------------------- - -Mongoid 7.4 with the ``Mongoid.broken_and`` option set to ``false`` -will preserve existing conditions when using ``and`` to add new conditions -to a query when the same operator is used on the same field multiple times. -For example, in the following query: - -.. code-block:: ruby - - Band.where(id: 1).and({year: {'$in' => [2020]}}, {year: {'$in' => [2021]}}).where(id: 2) - -Mongoid 7.4 with the ``Mongoid.broken_and`` option set to ``false`` will -generate the following criteria: - -.. code-block:: ruby - - #1, "year"=>{"$in"=>[2020]}, "$and"=>[{"year"=>{"$in"=>[2021]}}, {"_id"=>2}]} - options: {} - class: Band - embedded: false> - -In Mongoid 7.3 and earlier, and in 7.4 with the ``Mongoid.broken_and`` -option set to ``true`` (the default), the following criteria would be -generated instead which omit the {"$in" => [2021]} condition: - -.. code-block:: ruby - - 1, "year"=>{"$in"=>[2020]}, "$and"=>[{"_id"=>2}]} - options: {} - class: Band - embedded: false> - -.. note:: - - In Mongoid 8.0, the default value of the ``Mongoid.broken_and`` option will - change to ``false``. - - -Restore Parent Scope When Exiting ``with_scope`` Block ------------------------------------------------------- - -Mongoid 7.4 with the ``Mongoid.broken_scoping`` option set to ``false`` -will restore the parent scope when exiting a ``with_scope`` block. -For example: - -.. code-block:: ruby - - Band.with_scope(year: 2020) do - Band.with_scope(active: true) do - # ... - end - - # {year: 2020} condition is applied here - end - -In Mongoid 7.3 and earlier, and in 7.4 with the ``Mongoid.broken_scoping`` -option set to ``true`` (the default), once any ``with_scope`` block finishes, -all scopes are cleared: - -.. code-block:: ruby - - Band.with_scope(year: 2020) do - Band.with_scope(active: true) do - # ... - end - - # No scope is applied here - end - -.. note:: - - In Mongoid 8.0, the default value of the ``Mongoid.broken_scoping`` option will - change to ``false``. - - -Changes to ``distinct`` and ``pluck`` -------------------------------------- - -Respect Field Aliases In Embedded Documents When Using ``distinct`` and ``pluck`` -````````````````````````````````````````````````````````````````````````````````` - -When ``distinct`` and ``pluck`` are used with aliased fields in embedded -documents, the aliases can be expanded if the ``Mongoid.broken_alias_handling`` -option is set to ``false``. By default, for backwards compatibility, in -Mongoid 7.4 this option is set to true, yielding Mongoid 7.3 and earlier -behavior. Given the following definitions: - -.. code-block:: ruby - - class Band - include Mongoid::Document - embeds_many :managers - end - - class Manager - include Mongoid::Document - embedded_in :band - - field :name, as: :n - end - -Mongoid 7.4 behavior with ``Mongoid.broken_alias_handling`` set to ``false``: - -.. code-block:: ruby - - # Expands out to "managers.n" in the query: - Band.distinct('managers.name') - Band.pluck('managers.name') - -Mongoid 7.3 and 7.4 with ``Mongoid.broken_alias_handling`` set to ``true`` behavior: - -.. code-block:: ruby - - # Sends "managers.name" without expanding the alias: - Band.distinct('managers.name') - Band.pluck('managers.name') - -.. note:: - - The alias expansion for top-level fields has already been done by Mongoid 7.3. - -.. note:: - - In Mongoid 8.0, the default value of the ``Mongoid.broken_alias_handling`` option will - change to ``false``. - - -Demongoize Values Returned from ``pluck`` and ``distinct`` -`````````````````````````````````````````````````````````` - -Mongoid 7.4 with the ``Mongoid.legacy_pluck_distinct`` option set to ``false`` -will demongoize values returned from the ``pluck`` and ``distinct`` methods. -Given the following definitions: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :sales, type: BigDecimal - end - - Band.create!(sales: "1E2") - Band.create!(sales: "2E2") - -Mongoid 7.4 behavior with ``Mongoid.legacy_pluck_distinct`` set to ``false``: - -.. code-block:: ruby - - Band.pluck(:sales) - # => [0.1e3, 0.2e3] - Band.distinct(:sales) - # => [0.1e3, 0.2e3] - - -In Mongoid 7.3 and earlier, and in 7.4 with the ``Mongoid.legacy_pluck_distinct`` -option set to ``true`` (the default), the value returned from the pluck and -distinct methods will not be demongoized. For example: - -.. code-block:: ruby - - Band.pluck(:sales) - # => ["1E2", "2E2"] - Band.distinct(:sales) - # => ["1E2", "2E2"] - -.. note:: - - In Mongoid 8.0, the default value of the ``Mongoid.legacy_pluck_distinct`` option will - change to ``false``. - - -Localized Fields with ``pluck`` and ``distinct`` -```````````````````````````````````````````````` -Mongoid 7.4 with the ``Mongoid.legacy_pluck_distinct`` option set to ``false`` -changes the behavior of using ``pluck`` and ``distinct`` with localized fields. -Now, when retrieving a localized field using these methods, the translation for -the current locale will be returned. To get the full translations hash the -``_translations`` field can be used. Given the following definitions: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :name, localize: true - end - - I18n.locale = :en - band = Band.create!(name: 'english-name') - I18n.locale = :de - band.name = 'deutsch-name' - band.save! - -Mongoid 7.4 behavior with ``Mongoid.legacy_pluck_distinct`` set to ``false``: - -.. code-block:: ruby - - Band.pluck(:name) - # => ["deutsch-name"] - Band.pluck(:name_translations) - # => [{"en"=>"english-name", "de"=>"deutsch-name"}, {"en"=>"english-name", "de"=>"deutsch-name"}] - -In Mongoid 7.3 and earlier, and in 7.4 with the ``Mongoid.legacy_pluck_distinct`` -option set to ``true`` (the default), inputting a localized field returns the -full translations hash. Inputting the ``_translations`` field will return ``nil``. -For example: - -.. code-block:: ruby - - Band.pluck(:name) - # => [{"en"=>"english-name", "de"=>"deutsch-name"}, {"en"=>"english-name", "de"=>"deutsch-name"}] - Band.pluck(:name_translations) - # => [nil, nil] - -.. note:: - - In Mongoid 8.0, the default value of the ``Mongoid.legacy_pluck_distinct`` option will - change to ``false``. - - -Embedded Fields with ``pluck`` -`````````````````````````````` -Mongoid 7.4 with the ``Mongoid.legacy_pluck_distinct`` option set to ``false`` -returns the embedded values themselves, i.e. not inside a hash. Given the -following definitions: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - embeds_one :label - end - - class Label - include Mongoid::Document - - embedded_in :band - field :sales, type: BigDecimal - end - -Mongoid 7.4 behavior with ``Mongoid.legacy_pluck_distinct`` set to ``false``: - -.. code-block:: ruby - - Band.pluck("label.sales") - # => [0.1e3] - -In Mongoid 7.3 and earlier, and in 7.4 with the ``Mongoid.legacy_pluck_distinct`` -option set to ``true`` (the default), plucking embedded attributes returns them -inside a hash. For example: - -.. code-block:: ruby - - Band.pluck("label.sales") - # => [{"sales"=>"1E2"}] - -.. note:: - - In Mongoid 8.0, the default value of the ``Mongoid.legacy_pluck_distinct`` option will - change to ``false``. - - -``update_one`` Warnings in ``upsert`` -------------------------------------- - -Mongoid 7.4.1 fixes incorrect usage of the driver's ``update_one`` method from -Mongoid's ``upsert`` method. Mongoid's ``upsert`` actually performs a -replacing upsert, and Mongoid 7.4.1 and later correctly call ``replace_one``. diff --git a/docs/release-notes/mongoid-7.5.txt b/docs/release-notes/mongoid-7.5.txt deleted file mode 100644 index b02da6ed09..0000000000 --- a/docs/release-notes/mongoid-7.5.txt +++ /dev/null @@ -1,273 +0,0 @@ -.. _mongoid-7.5: - -*********** -Mongoid 7.5 -*********** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -This page describes significant changes and improvements in Mongoid 7.5. -The complete list of releases is available `on GitHub -`_ and `in JIRA -`_; -please consult GitHub releases for detailed release notes and JIRA for -the complete list of issues fixed in each release, including bug fixes. - - -Ruby, JRuby and Rails Version Support -------------------------------------- - -Mongoid 7.5 deprecates support for Ruby 2.5, JRuby 9.2 and Rails 5.1. -Mongoid 8 will require Ruby 2.6 or newer, JRuby 9.3 or newer and Rails 5.2 or -newer. - - -Feature Flags Summary ---------------------- - -To ensure a stable upgrade path from Mongoid 7.4, Mongoid 7.5 -introduces feature flags which are further explained in the -sections below. - -To enable all new behavior in Mongoid 7.5, please use the following -:ref:`configuration options ` in your mongoid.yml file. -We recommend newly created apps to do this as well. - -.. code-block:: yaml - - development: - ... - options: - # Enable all new behavior in Mongoid 7.5 - legacy_attributes: false - overwrite_chained_operators: false - -In addition, please refer to the release notes of earlier 7.x versions for -feature flags introduced in each version. For clarity, Mongoid 7.5 does -not switch the behavior of any previously introduced feature flag. - - -Implemented ``Criteria#take/take!`` Method ------------------------------------------- - -Mongoid 7.5 introduces the ``#take`` method which returns a document -or a set of documents from the database without ordering by ``_id``: - -.. code:: ruby - - class Band - include Mongoid::Document - end - - Band.create! - Band.create! - - Band.take - # => # - Band.take(2) - # => [ #, # ] - -If a parameter is given to ``#take``, an array of documents is returned. If no parameter is -given, a singular document is returned. - -The ``#take!`` method functions the same as calling ``#take`` without arguments, -but raises an DocumentNotFound error instead of returning nil if no documents -are found. - -.. code:: ruby - - Band.take! - # => # - -Note that the ``#take/take!`` methods do not apply a sort to the view before -retrieving the documents from the database, and therefore they may return different -results than the ``#first`` and ``#last`` methods. ``#take`` is equivalent to -calling ``#first`` or ``#last`` with the ``{ id_sort: :none }`` option. This -option has been deprecated in Mongoid 7.5 and it is recommended to use ``#take`` -instead going forward. Support for the ``:id_sort`` option will be dropped in -Mongoid 8. - - -Force the ``attributes`` Method to Always Return a ``Hash`` ------------------------------------------------------------ - -Mongoid 7.5 with the ``Mongoid.legacy_attributes`` option set to ``false`` -will always return a ``Hash`` when calling the ``attributes`` method. -For example: - -.. code-block:: ruby - - class Band - include Mongoid::Document - - field :name - end - - band = Band.create!(name: "The Rolling Stones") - p band.attributes.class - # => Hash - - band = Band.first - p band.attributes.class - # => Hash - -In Mongoid 7.4 and earlier, and in 7.5 with the ``Mongoid.legacy_attributes`` -option set to ``true``, the ``attributes`` method on a document will return a -``BSON::Document`` when retrieving that document from the database, but will -return a ``Hash`` when instantiating a new document: - -.. code-block:: ruby - - band = Band.create!(name: "The Rolling Stones") - p band.attributes.class - # => Hash - - band = Band.first - p band.attributes.class - # => BSON::Document - - -Deprecate ``:id_sort`` Option and Support ``limit`` on ``#first/last`` ----------------------------------------------------------------------- - -Mongoid 7.5 deprecates the ``:id_sort`` keyword argument for the -``Criteria#first`` and ``Criteria#last`` methods. Please use ``Criteria#take`` -to retrieve documents without sorting by id. - -The ``first`` and ``last`` methods now take the number of documents to return -as a positional argument, mirroring the functionality of Ruby's ``Enumerable`` -method and ActiveRecord's ``first`` and ``last`` methods. Both invocations -(with limit as a positional arguments and with the ``:id_sort`` option) remain -supported in Mongoid 7.x, but the ``:id_sort`` invocation will be removed in -Mongoid 8. - -.. code:: ruby - - Band.first - # => # - Band.first(2) - # => [ #, # ] - Band.last - # => # - Band.last(2) - # => [#, #] - -When providing a limit, ``#first/last`` will return a list of documents, and -when not providing a limit (or providing ``nil``), a single document will be -returned. - -Note that the ``#first/last`` methods apply a sort on ``_id``, which can -cause performance issues. To get a document without sorting first, use the -``Critera#take`` method. - - -Combine Chained Operators Using ``and`` Instead of ``override`` ---------------------------------------------------------------- - -Mongoid 7.5 with the ``Mongoid.overwrite_chained_operators`` option set to ``false`` -will combine conditions that use the same operator and field using an ``and``. -For example, in the following query: - -.. code-block:: ruby - - Band.ne(name: "The Rolling Stones").ne(name: "The Beatles") - -Mongoid 7.5 with the ``Mongoid.overwrite_chained_operators`` option set to ``false`` -will generate the following criteria: - -.. code-block:: ruby - - #{"$ne"=>"The Rolling Stones"}, "$and"=>[{"name"=>{"$ne"=>"The Beatles"}}]} - options: {} - class: Band - embedded: false> - -In Mongoid 7.4 and earlier, and in 7.5 with the ``Mongoid.overwrite_chained_operators`` -option set to ``true``, the following criteria would be generated instead which -overwrites the first condition: - -.. code-block:: ruby - - #{"$ne"=>"The Beatles"}} - options: {} - class: Band - embedded: false> - -The following functions are affected by this change: - -- ``eq`` -- ``elem_match`` -- ``gt`` -- ``gte`` -- ``lt`` -- ``lte`` -- ``mod`` -- ``ne`` -- ``near`` -- ``near_sphere`` - -.. note:: - - In Mongoid 7.5 with the ``Mongoid.overwrite_chained_operators`` option set to - ``false``, nested keys in the generated selector will always be strings, - whereas in Mongoid 7.4 and earlier, and in 7.5 with the - ``Mongoid.overwrite_chained_operators`` option set to ``true``, nested keys in - the selector can be strings or symbols, depending on what was passed to the - operator. - - -``pluck`` Usage of ``map`` Deprecated -------------------------------------- - -Mongoid 7.5 deprecates the usage of ``map`` as pluck, as in the following -example: - -.. code-block:: ruby - - Band.all.map(:name) - - # Equivalent to: - Band.pluck(:name) - -This usage will no longer be supported in Mongoid 8, which will not accept -arguments to ``map``. - - -``Mongoid::Criteria`` cache deprecated --------------------------------------- - -The ability to cache individual criteria objects has been deprecated in Mongoid -7.5 and will be dropped in Mongoid 8. - -In order to get caching functionality, enable the Mongoid QueryCache. See the -section on :ref:`QueryCache ` for more details. - - -``Array#update_values`` and ``Hash#update_values`` deprecated -------------------------------------------------------------- - -The ``Array#update_values`` and ``Hash#update_values`` methods are deprecated in -Mongoid 7.5. It is recommended to use ActiveSupport's ``transform_values!`` -method instead. - - -``Document#to_a`` deprecated ----------------------------- - -The ``Document#to_a`` method is deprecated in Mongoid 7.5. - - -``update_one`` Warnings in ``upsert`` -------------------------------------- - -Mongoid 7.5 fixes incorrect usage of the driver's ``update_one`` method from -Mongoid's ``upsert`` method. Mongoid's ``upsert`` actually performs a -replacing upsert, and Mongoid 7.5 correctly calls ``replace_one``. diff --git a/docs/release-notes/mongoid-8.0.txt b/docs/release-notes/mongoid-8.0.txt deleted file mode 100644 index f0e593e712..0000000000 --- a/docs/release-notes/mongoid-8.0.txt +++ /dev/null @@ -1,826 +0,0 @@ -.. _mongoid-8.0: - -*********** -Mongoid 8.0 -*********** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -This page describes significant changes and improvements in Mongoid 8.0. -The complete list of releases is available `on GitHub -`_ and `in JIRA -`_; -please consult GitHub releases for detailed release notes and JIRA for -the complete list of issues fixed in each release, including bug fixes. - - -Support for MongoDB 3.4 and Earlier Servers Dropped ---------------------------------------------------- - -Mongoid 8 requires MongoDB 3.6 or newer. Earlier server versions are not -supported. - - -Support for Ruby 2.5 Dropped ----------------------------- - -Mongoid 8 requires Ruby 2.6 or newer. Earlier Ruby versions are not supported. - - -Support for Rails 5.1 Dropped ------------------------------ - -Mongoid 8 requires Rails 5.2 or newer. Earlier Rails versions are not supported. - - -Default Option Values Changed ------------------------------ - -**Breaking change:** The following options have had their default values -changed in Mongoid 8.0: - -- ``:broken_aggregables`` => ``false`` -- ``:broken_alias_handling`` => ``false`` -- ``:broken_and`` => ``false`` -- ``:broken_scoping`` => ``false`` -- ``:broken_updates`` => ``false`` -- ``:compare_time_by_ms`` => ``true`` -- ``:legacy_attributes`` => ``false`` -- ``:legacy_pluck_distinct`` => ``false`` -- ``:legacy_triple_equals`` => ``false`` -- ``:object_id_as_json_oid`` => ``false`` -- ``:overwrite_chained_operators`` => ``false`` - -Please refer to :ref:`configuration option ` for -the description and effects of each of these options. - - -``Decimal128``-backed ``BigDecimal`` Fields -------------------------------------------- - -Mongoid 8 introduces the ``map_big_decimal_to_decimal128`` feature flag, which -allows values assigned to a field of type ``BigDecimal`` to be stored as type -``String`` in the database for compatibility with Mongoid 7 and earlier. In -Mongoid 8 by default (with this feature flag turned on), values assigned to -fields of type ``BigDecimal`` are stored in the database as type -``BSON::Decimal128``. In Mongoid 7 and earlier, and in Mongoid 8 with this -feature flag turned off, values assigned to fields of type ``BigDecimal`` are -stored as Strings. See the section on :ref:`BigDecimal Fields ` -for more details. - - -Storing/Retrieving/Evolving Uncastable Values ---------------------------------------------- - -**Breaking change:** In Mongoid 8, Mongoid standardizes the storing, retrieving -and evolving of "uncastable values." On attempting to read or write an -uncastable value, a ``nil`` is returned or written instead. When attempting to -evolve an uncastable value, the inputted value is returned. See the section on -:ref:`Uncastable Values ` for more details. - -Some ``mongoize``, ``demongoize`` and ``evolve`` methods were also changed to -perform consistently with rails and the other ``mongoize``, ``demongoize`` and -``evolve`` methods. The following table shows the changes in functionality: - -.. list-table:: - :widths: 1 2 2 2 - :stub-columns: 1 - :header-rows: 1 - - * - Field Type - - Situation - - Previous Functionality - - New Functionality - - * - | Boolean - - | When a non-boolean string is assigned: "bogus value" - - | return ``false`` - - | return ``nil`` - - * - Array/Hash - - When a value that is not an array or hash is assigned - - raise ``InvalidValue`` error - - return ``nil`` - - * - | Set - - | When a value that is not a set is assigned: 1 - - | raise ``NoMethodError`` Exception: undefined method ``to_a`` for 1:Integer - - | return ``nil`` - - * - Regexp - - When persisting and reading a Regexp from the database - - return a ``BSON::Regexp::Raw`` - - return a ``Regexp`` - - * - | Time/DateTime - - | When assigning a bogus value: ``:bogus`` - - | raise ``NoMethodError`` Exception: undefined method ``to_i`` for :bogus:Symbol - - | return ``nil`` - - * - Time/DateTime - - When demongoizing a non-Time value: "bogus", ``Date.today`` - - raise ``NoMethodError`` Exception: undefined method ``getlocal`` for "bogus":String - - "bogus": return ``nil`` - - ``Date.today``: return ``Time/DateTime`` - - * - | Date - - | When assigning or demongoizing a bogus value: :bogus - - | raise ``NoMethodError`` Exception: undefined method ``year`` for :bogus:Symbol - - | return ``nil`` - - * - Time/DateTime/Date - - When demongoizing a valid string: "2022-07-14 14:45:51 -0400" - - raise ``NoMethodError`` Exception: undefined method ``getlocal`` for "2022-07-14 14:45:51 -0400":String - - return a ``Time/DateTime/Date`` - - * - | All Types - - | When an uncastable value is assigned or demongoized - - | undefined behavior, occasionally raise ``NoMethodError`` - - | return ``nil`` - - * - All Types - - When an uncastable value is evolved - - undefined behavior, occasionally raise ``NoMethodError`` - - return inputted value - -.. note:: - - The ``demongoize`` methods on container objects (i.e. Hash, Array) have not - changed to prevent bugs when modifying and saving those objects. See - https://jira.mongodb.org/browse/MONGOID-2951 for a longer discussion on these - bugs. - -Changes to the ``attributes_before_type_cast`` Hash ---------------------------------------------------- - -The ``attributes_before_type_cast`` hash has been changed to function more like -ActiveRecord: - -- On instantiation of a new model (without parameters), the - ``attributes_before_type_cast`` hash has the same contents as the - ``attributes`` hash. If parameters are passed to the initializer, those - values will be stored in the ``attributes_before_type_cast`` hash before - they are ``mongoized``. -- When assigning a value to the model, the ``mongoized`` value (i.e. when - assiging '1' to an Integer field, it is ``mongoized`` to 1) is stored in - the ``attributes`` hash, whereas the raw value (i.e. '1') is stored in the - ``attributes_before_type_cast`` hash. -- When saving, creating (i.e. using the ``create!`` method), or reloading the - model, the ``attributes_before_type_cast`` hash is reset to have the same - contents as the ``attributes`` hash. -- When reading a document from the database, the ``attributes_before_type_cast`` - hash contains the attributes as they appear in the database, as opposed to - their ``demongoized`` form. - - -Order of Callback Invocation ----------------------------- - -**Breaking change:** Mongoid 8.0 changes the order of _create and _save callback -invocation for documents with associations. - -Referenced associations (``has_one`` and ``has_many``): - -.. list-table:: - :header-rows: 1 - :widths: 50 50 - - * - Mongoid 8.0 - - Mongoid 7 - - * - | Parent :before_save - - | Parent :before_save - - * - Parent :around_save_open - - Parent :around_save_open - - * - | Parent :before_create - - | Parent :before_create - - * - Parent :around_create_open - - Parent :around_create_open - - * - | **Parent persisted in MongoDB** - - | **Parent persisted in MongoDB** - - * - Child :before_save - - Parent :around_create_close - - * - | Child :around_save_open - - | Parent :after_create - - * - Child :before_create - - Child :before_save - - * - | Child :around_create_open - - | Child :around_save_open - - * - - - Child :before_create - - * - | - - | Child :around_create_open - - * - **Child persisted in MongoDB** - - **Child persisted in MongoDB** - - * - | Child :around_create_close - - | Child :around_create_close - - * - Child :after_create - - Child :after_create - - * - | Child :around_save_close - - | Child :around_save_close - - * - Child :after_save - - Child :after_save - - * - | Parent :around_create_close - - | Parent :around_save_close - - * - Parent :after_create - - Parent :after_save - - * - | Parent :around_save_close - - | - - * - Parent :after_save - - - -Embedded associations (``embeds_one`` and ``embeds_many``): - -.. list-table:: - :header-rows: 1 - :widths: 50 50 - - * - Mongoid 8.0 - - Mongoid 7 - - * - | Parent :before_save - - | Child :before_save - - * - Parent :around_save_open - - Child :around_save_open - - * - | Parent :before_create - - | Child :around_save_close - - * - Parent :around_create_open - - Child :after_save - - * - | Child :before_save - - | Parent :before_save - - * - Child :around_save_open - - Parent :around_save_open - - * - | Child :before_create - - | Child :before_create - - * - Child :around_create_open - - Child :around_create_open - - * - | - - | Child :around_create_close - - * - - - Child :after_create - - * - | - - | Parent :before_create - - * - - - Parent :around_create_open - - * - | **Document persisted in MongoDB** - - | **Document persisted in MongoDB** - - * - Child :around_create_close - - - - * - | Child :after_create - - | - - * - Child :around_save_close - - - - * - | Child :after_save - - | - - * - Parent :around_create_close - - Parent :around_create_close - - * - | Parent :after_create - - | Parent :after_create - - * - Parent :around_save_close - - Parent :around_save_close - - * - | Parent :after_save - - | Parent :after_save - -``Changeable`` Module Behavior Made Compatible With ``ActiveModel::Dirty`` --------------------------------------------------------------------------- - -When updating documents, it is now possible to get updated attribute values -in ``after_*`` callbacks. This follows ActiveRecord/ActiveModel behavior. - -.. code-block:: ruby - - class Cat - include Mongoid::Document - - field :age, type: Integer - - after_save do - p self - p attribute_was(:age) - end - end - - a = Cat.create! - a.age = 2 - a.save! - -Mongoid 8.0 output: - -.. code-block:: ruby - - # - 2 - - -Mongoid 7 output: - -.. code-block:: ruby - - # - nil - -Notice that in 7 ``attribute_was(:age)`` returns the old attribute value, -while in 8.0 ``attribute_was(:age)`` returns the new value. - - -``*_previously_was``, ``previously_new_record?``, and ``previously_persisted?`` helpers ---------------------------------------------------------------------------------------- - -Mongoid 8.0 introduces ActiveModel-compatible ``*_previously_was`` helpers, -as well as ActiveRecord-compatible ``previously_new_record?`` and -``previously_persisted?`` helpers: - -.. code-block:: ruby - - class User - include Mongoid::Document - - field :name, type: String - field :age, type: Integer - end - - user = User.create!(name: 'Sam', age: 18) - user.previously_new_record? # => true - - user.name = "Nick" - user.save! - user.name_previously_was # => "Sam" - user.age_previously_was # => 18 - user.previously_new_record? # => false - - user.destroy - user.previously_persisted? # => true - - -Unknown Field Type Symbols/Strings Prohibited ---------------------------------------------- - -**Breaking change:** Mongoid 8 prohibits using symbols and strings as field -types when these symbols and strings do not map to a known type. Previously -such usage would create a field of type ``Object``. - -Mongoid 8 behavior: - -.. code-block:: ruby - - class User - include Mongoid::Document - - field :name, type: :bogus - # => raises Mongoid::Errors::InvalidFieldType - end - -Mongoid 7 behavior: - -.. code-block:: ruby - - class User - include Mongoid::Document - - field :name, type: :bogus - # Equivalent to: - field :name - end - - -``any_of`` Adds Multiple Arguments As Top-Level Conditions ----------------------------------------------------------- - -**Breaking change:** When ``any_of`` is invoked with multiple conditions, the -conditions are now added to the top level of the criteria, same as when -``any_of`` is invoked with a single condition. Previously when multiple -conditions were provided, and the criteria already had an ``$or`` operator, -the new conditions would be added to the existing ``$or`` as an additional -branch. - -Mongoid 8.0 behavior: - -.. code-block:: ruby - - Band.any_of({name: 'The Rolling Stones'}, {founded: 1990}). - any_of({members: 2}, {last_tour: 1995}) - # => - # #[{"name"=>"The Rolling Stones"}, {"founded"=>1990}], - # "$and"=>[{"$or"=>[{"members"=>2}, {"last_tour"=>1995}]}]} - # options: {} - # class: Band - # embedded: false> - - Band.any_of({name: 'The Rolling Stones'}, {founded: 1990}).any_of({members: 2}) - # => - # #[{"name"=>"The Rolling Stones"}, {"founded"=>1990}], "members"=>2} - # options: {} - # class: Band - # embedded: false> - -Mongoid 7 behavior: - -.. code-block:: ruby - - Band.any_of({name: 'The Rolling Stones'}, {founded: 1990}). - any_of({members: 2}, {last_tour: 1995}) - # => - # #[{"name"=>"The Rolling Stones"}, {"founded"=>1990}, - # {"members"=>2}, {"last_tour"=>1995}]} - # options: {} - # class: Band - # embedded: false> - - Band.any_of({name: 'The Rolling Stones'}, {founded: 1990}).any_of({members: 2}) - # => - # #[{"name"=>"The Rolling Stones"}, {"founded"=>1990}], "members"=>2} - # options: {} - # class: Band - # embedded: false> - - -``#pluck`` on Embedded Criteria Returns ``nil`` Values ------------------------------------------------------- - -Mongoid 8 fixes a bug where calling ``#pluck`` on a Mongoid::Criteria -for embedded documents discarded nil values. This behavior was -inconsistent with both the ``#pluck`` method in ActiveSupport and -with how ``#pluck`` works when reading documents from the database. - -Mongoid 8.0 behavior: - -.. code-block:: ruby - - class Address - include Mongoid::Document - - embedded_in :mall - - field :street, type: String - end - - class Mall - include Mongoid::Document - - embeds_many :addresses - end - - mall = Mall.create! - mall.addresses.create!(street: "Elm Street") - mall.addresses.create!(street: nil) - - # Pluck from embedded document criteria - mall.addresses.all.pluck(:street) - #=> ['Elm Street', nil] - -Mongoid 7 behavior, given the same setup: - -.. code-block:: ruby - - # Pluck from embedded document criteria - mall.addresses.all.pluck(:street) - #=> ['Elm Street'] - -For clarity, the following behavior is unchanged from Mongoid 7 to Mongoid 8.0: - -.. code-block:: ruby - - # Pluck from database - Mall.all.pluck('addresses.street') - #=> [ ['Elm Street', nil] ] - - # Pluck using ActiveSupport Array#pluck - mall.addresses.pluck(:street) - #=> ['Elm Street', nil] - - -Replaced ``Mongoid::Criteria#geo_spacial`` with ``#geo_spatial`` ----------------------------------------------------------------- - -The previously deprecated ``Mongoid::Criteria#geo_spacial`` method has been -removed in Mongoid 8. It has been replaced one-for-one with ``#geo_spatial`` -which was added in Mongoid 7.2.0. - - -Implemented ``.tally`` method on ``Mongoid#Criteria`` ------------------------------------------------------ - -Mongoid 8 implements the ``.tally`` method on ``Mongoid#Criteria``. ``tally`` -takes a field name as a parameter and returns a mapping from values to their -counts. For example, take the following model: - -.. code:: - - class User - include Mongoid::Document - field :age - end - -and the following documents in the database: - -.. code:: - - { _id: 1, age: 21 } - { _id: 2, age: 21 } - { _id: 3, age: 22 } - -Calling ``tally`` on the age field yields the following: - -.. code:: - - User.tally("age") - # => { 21 => 2, 22 => 1 } - -The ``tally`` method accepts the dot notation and field aliases. It also -allows for tallying localized fields. - - -Implemented ``.pick`` method on ``Mongoid#Criteria`` ------------------------------------------------------ - -Mongoid 8 implements the ``.pick`` method on ``Mongoid#Criteria``. ``pick`` -takes one or more field names as a parameter and returns the values for those -fields from one document. Consider the following model: - -.. code:: - - class User - include Mongoid::Document - field :age - end - -and the following documents in the database: - -.. code:: - - { _id: 1, age: 21 } - { _id: 2, age: 21 } - { _id: 3, age: 22 } - -Calling ``pick`` on the age field yields the following: - -.. code:: - - User.pick(:age) - # => 21 - -This method does not apply a sort to the documents, so it will not necessarily -return the values from the first document. - -The ``pick`` method accepts the dot notation and field aliases. It also -allows for picking localized fields. - - -``find`` delegates to ``Enumerable#find`` when given a block ------------------------------------------------------------- - -When given a block, without ``_id`` arguments, ``find`` delegates to -``Enumerable#find``. Consider the following model: - -.. code:: - - class Band - include Mongoid::Document - field :name, type: String - end - - Band.create!(name: "Depeche Mode") - Band.create!(name: "The Rolling Stones") - -Calling ``find`` with a block returns the first document for which the block -returns ``true``: - -.. code:: - - Band.find do |b| - b.name == "Depeche Mode" - end - # => # - - -No Longer Persisting Documents with Invalid ``belongs_to`` Associations ------------------------------------------------------------------------ - -In Mongoid 8, if an invalid document is assigned to a ``belongs_to`` association, -and the base document is saved, if the ``belongs_to`` association had the -option ``optional: false`` or ``optional`` is unset and the global flag -``belongs_to_required_by_default`` is true, neither the document nor the -associated document will be persisted. For example, given the following -models: - -.. code:: - - class Parent - include Mongoid::Document - has_one :child - field :name - validates :name, presence: true - end - - class Child - include Mongoid::Document - - belongs_to :parent, autosave: true, validate: false, optional: false - end - - child = Child.new - parent = Parent.new - child.parent = parent # parent is invalid, it does not have a name - child.save - -In this case, both the child and the parent will not be persisted. - -.. note:: - If ``save!`` were called, a validation error would be raised. - -If optional is false, then the Child will be persisted with a parent_id, but the -parent will not be persisted: - -.. code:: - - child = Child.new - parent = Parent.new - child.parent = parent # parent is invalid, it does not have a name - child.save - - p Child.first - # => - p Parent.first - # => nil - -If you want the functionality of neither document being persisted in Mongoid 7 or 8 -and earlier, the ``validate: true`` option can be set on the association. If -you want the functionality of only the Child being persisted, the ``validate: -false`` option can be set on the association. - - -Update Local HABTM Association Correctly ----------------------------------------- - -In Mongoid 8, when pushing persisted elements to a HABTM association, the -association will now update correctly without requiring a reload. -For example: - -.. code:: - - class User - include Mongoid::Document - has_and_belongs_to_many :posts - end - - class Post - include Mongoid::Document - has_and_belongs_to_many :users - end - - user1 = User.create! - user2 = User.create! - - post = user1.posts.create! - - p post.users.length - # => 1 - - post.users << user2 - - p post.users.length - # => 1 in Mongoid 7, 2 in Mongoid 8 - - p post.reload.users.length - # => 2 - -As you can see from this example, after pushing ``user2`` to the users array, -Mongoid 8 correctly updates the number of elements without requiring a reload. - - -Repaired Storing Strings in BSON::Binary fields ------------------------------------------------ - -**Breaking change:** In Mongoid 8, storing a String in a field of type -``BSON::Binary`` will be stored in and returned from the database as a -``BSON::Binary``. Prior to Mongoid 8 it was stored and returned as a String: - -.. code:: - - class Registry - include Mongoid::Document - field :data, type: BSON::Binary - end - - registry = Registry.create!(data: "data!") - p registry.data - # => Mongoid 7: "data!" - # => Mongoid 8: - - registry = Registry.find(registry.id) - p registry.data - # => Mongoid 7: "data!" - # => Mongoid 8: - - -Removed ``Document#to_a`` Method --------------------------------- - -The previously deprecated ``Document#to_a`` method has been removed in -Mongoid 8. - - -Removed ``:drop_dups`` Option from Indexes ------------------------------------------- - -The ``:drop_dups`` option has been removed from the ``index`` macro. This option -was specific to MongoDB server 2.6 and earlier, which Mongoid no longer supports. - - -Removed ``Mongoid::Errors::EagerLoad`` Exception Class ------------------------------------------------------- - -The previously deprecated ``Mongoid::Errors::EagerLoad`` exception class -has been removed in Mongoid 8. It has not been used by Mongoid since -version 7.1.1 when eager loading for polymorphic ``belongs_to`` associations -was implemented. - - -Removed Deprecated Constants ----------------------------- - -Mongoid 8 removes the following deprecated constants that are not expected -to have been used outside of Mongoid: - -- ``Mongoid::Extensions::Date::EPOCH`` -- ``Mongoid::Extensions::Time::EPOCH`` -- ``Mongoid::Factory::TYPE`` - - -Removed ``Array#update_values`` and ``Hash#update_values`` methods ------------------------------------------------------------------- - -The previously deprecated ``Array#update_values`` and ``Hash#update_values`` -methods have been removed in Mongoid 8. - - -Deprecated the ``geoHaystack``, ``geoSearch`` Options ------------------------------------------------------ - -The ``geoHaystack`` and ``geoSearch`` options on indexes have been deprecated. - - -``:id_sort`` Option on ``#first/last`` Removed ----------------------------------------------- - -Support for the ``:id_sort`` option on the ``#first`` and ``#last`` options has -been dropped. These methods now only except a limit as a positional argument. - - -Mongoid::Criteria Cache Removed -------------------------------- - -Support for individually caching criteria objects has been dropped in Mongoid 8. - -In order to get caching functionality, enable the Mongoid Query Cache. See the -section on :ref:`Query Cache ` for more details. diff --git a/docs/release-notes/mongoid-8.1.txt b/docs/release-notes/mongoid-8.1.txt deleted file mode 100644 index 5c69df809b..0000000000 --- a/docs/release-notes/mongoid-8.1.txt +++ /dev/null @@ -1,431 +0,0 @@ -.. _mongoid-8.1: - -*********** -Mongoid 8.1 -*********** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -This page describes significant changes and improvements in Mongoid 8.1. -The complete list of releases is available `on GitHub -`_ and `in JIRA -`_; -please consult GitHub releases for detailed release notes and JIRA for -the complete list of issues fixed in each release, including bug fixes. - -Added ``load_async`` method on ``Criteria`` to asynchronously load documents ----------------------------------------------------------------------------- - -The new ``load_async`` method on ``Criteria`` allows :ref:`running database queries asynchronously `. - - -Added ``attribute_before_last_save``, ``saved_change_to_attribute``, ``saved_change_to_attribute?``, and ``will_save_change_to_attribute?`` methods ----------------------------------------------------------------------------------------------------------------------------------------------------- - -These new methods behave identically to corresponding methods -from ``ActiveRecord::AttributeMethods::Dirty``. The methods are particularly useful in -callbacks: - -.. code-block:: ruby - - class Person - include Mongoid::Document - - field :name, type: String - - before_save do - puts "attribute_was(:name): #{attribute_was(:name)}" - puts "attribute_before_last_save(:name): #{attribute_before_last_save(:name)}" - puts "will_save_change_to_attribute?(:name): #{will_save_change_to_attribute?(:name)}" - end - - after_save do - puts "attribute_was(:name): #{attribute_was(:name)}" - puts "attribute_before_last_save(:name): #{attribute_before_last_save(:name)}" - puts "saved_change_to_attribute(:name): #{saved_change_to_attribute(:name)}" - puts "attribute_changed?(:name): #{attribute_changed?(:name)}" - puts "saved_change_to_attribute?(:name): #{saved_change_to_attribute?(:name)}" - end - end - - person = Person.create(name: 'John') - # - # before_save - # - ## attribute_was(:name): nil - ## attribute_before_last_save(:name): nil - ## will_save_change_to_attribute?(:name): true - # - # after_save - # - ## attribute_was(:name): John => New value - ## attribute_before_last_save(:name): nil => Value before save - ## saved_change_to_attribute(:name): [nil, "John"] => Both values - ## attribute_changed?(:name): false - ## saved_change_to_attribute?(:name): true => Correctly indicates that the change for :name was saved - - person.name = 'Jane' - person.save - # - # before_save - # - ## attribute_was(:name): John => attribute_was not look back before the last save - ## attribute_before_last_save(:name): nil => value before the last save - ## will_save_change_to_attribute?(:name): true - # - # after_save - # - ## attribute_was(:name): Jane => New value - ## attribute_before_last_save(:name): John => Value before save - ## saved_change_to_attribute(:name): ["John", "Jane"] => Both values - ## attribute_changed?(:name): false - ## saved_change_to_attribute?(:name): true => Correctly indicates that the change for :name was saved - -For all of the new methods there are also shorter forms created dynamically, e.g. -``attribute_before_last_save(:name)`` is equivalent to ``name_before_last_save``, -``saved_change_to_attribute(:name)`` is equivalent to ``saved_change_to_name``, -``saved_change_to_attribute?(:name)`` is equivalent to ``saved_change_to_name?``, -and ``will_save_change_to_attribute?(:name)`` is equivalent to ``will_save_change_to_name?``. - - -Deprecated ``use_activesupport_time_zone`` config option --------------------------------------------------------- - -The config option ``use_activesupport_time_zone`` has been deprecated. -Beginning in Mongoid 9.0, it will be ignored and always behave as true. -Since ``use_activesupport_time_zone`` currently defaults to true, it is -safe to remove from your config file at this time. - - -Configuration DSL No Longer Requires an Argument to its Block -------------------------------------------------------------- - -It is now possible to use ``Mongoid.configure`` without -providing an argument to its block: - -.. code-block:: ruby - - Mongoid.configure do - connect_to("mongoid_test") - - # Use config method when assigning variables - config.preload_models = true - -Note that ``configure`` will continue to support a block argument. -The following is equivalent to the above: - -.. code-block:: ruby - - Mongoid.configure do |config| - config.connect_to("mongoid_test") - - config.preload_models = true - - -Added ``Mongoid::Criteria`` finder methods ------------------------------------------- - -Mongoid 8.1 implements several finder methods on ``Mongoid::Criteria``: - -- ``first!`` -- ``last!`` -- ``second/second!`` -- ``third/third!`` -- ``fourth/fourth!`` -- ``fifth/fifth!`` -- ``second_to_last/second_to_last!`` -- ``third_to_last/third_to_last!`` - -When no documents are found, methods without a bang (!) return nil, and methods -with a bang (!) raise an error: - -.. code:: ruby - - Band.none.first - # => nil - - Band.none.first! - # => raise Mongoid::Errors::DocumentNotFound - - -Added ``:touch`` option to ``#save`` ------------------------------------- - -Support for the ``:touch`` option has been added to the ``#save`` and ``#save!`` -methods. When this option is false, the ``updated_at`` field on the saved -document and all of it's embedded documents will not be updated with the -current time. When this option is true or unset, the ``updated_at`` field will -be updated with the current time. - -If the document being saved is a new document (i.e. it has not yet been -persisted to the database), then the ``:touch`` option will be ignored, and the -``updated_at`` (and ``created_at``) fields will be updated with the current -time. - - -Added Version Based Default Configuration ------------------------------------------ - -Mongoid 8.1 has added the ability to set the default configurations for a -specific version: - -.. code:: ruby - - Mongoid.configure do |config| - config.load_defaults 8.0 - end - -This is helpful for upgrading between versions. See the section on -:ref:`Version Based Default Configuration ` for more details on -how to use this feature to make upgrading between Mongoid versions easier. - - -Added ``:present`` option to localized fields ---------------------------------------------- - -The ``:present`` option was added to localized fields for removing blank values -from the ``_translations`` hash: - -.. code-block:: ruby - - class Product - include Mongoid::Document - field :description, localize: :present - end - -See the section on :ref:`Localize :present Field Option ` for -more details on how these are used. - - -Added ``:to`` and ``:from`` options to ``attribute_changed?`` -------------------------------------------------------------- - -Mongoid 8.1 adds the ``:to`` and ``:from`` options on the ``attribute_changed?`` -method. These options can be used to inquire whether the attribute has been changed -to or from a certain value: - -.. code: - - class Person - include Mongoid::Document - field :name, type: String - end - - person = Person.create!(name: "Trout") - person.name = "Ohtani" - - person.name_changed? - # => true - person.name_changed?(from: "Trout") - # => true - person.name_changed?(to: "Ohtani") - # => true - person.name_changed?(from: "Trout", to: "Ohtani") - # => true - person.name_changed?(from: "Trout", to: "Fletcher") - # => false - - -Allowed ``store_in`` to be called on subclasses ------------------------------------------------ - -Starting in Mongoid 8.1, subclasses can now specify which collection its -documents should be stored in using the ``store_in`` macro: - -.. code:: ruby - - class Shape - include Mongoid::Document - store_in collection: :shapes - end - - class Circle < Shape - store_in collection: :circles - end - - class Square < Shape - store_in collection: :squares - end - -Previously, an error was raised if this was done. See the section on -:ref:`Inheritance Persistence Context ` -for more details. - - -Added ``readonly!`` method and ``legacy_readonly`` feature flag ---------------------------------------------------------------- - -Mongoid 8.1 changes the meaning of read-only documents. In Mongoid 8.1 with -this feature flag turned off (``false``), a document becomes read-only when calling the -``readonly!`` method: - -.. code:: ruby - - band = Band.first - band.readonly? # => false - band.readonly! - band.readonly? # => true - band.name = "The Rolling Stones" - band.save # => raises ReadonlyDocument error - -With this feature flag turned off, a ``ReadonlyDocument`` error will be -raised when destroying or deleting, as well as when saving or updating. - -Prior to Mongoid 8.1 and in 8.1 with the ``legacy_readonly`` feature flag -turned on (``true``), documents become read-only when they are projected (i.e. using -``#only`` or ``#without``). - -.. code:: ruby - - class Band - include Mongoid::Document - field :name, type: String - field :genre, type: String - end - - band = Band.only(:name).first - band.readonly? # => true - band.destroy # => raises ReadonlyDocument error - -Note that with this feature flag on, a ``ReadonlyDocument`` error will only be -raised when destroying or deleting, and not on saving or updating. See the -section on :ref:`Read-only Documents ` for more details. - - -Added method parameters to ``#exists?`` ---------------------------------------- - -Mongoid 8.1 introduces method paramters to the ``Contextual#exists?`` method. -An _id, a hash of conditions, or ``false``/``nil`` can now be included: - -.. code:: ruby - - Band.exists? - Band.exists?(name: "The Rolling Stones") - Band.exists?(BSON::ObjectId('6320d96a3282a48cfce9e72c')) - Band.exists?(false) # always false - Band.exists?(nil) # always false - - -Added ``:replace`` option to ``#upsert`` ----------------------------------------- - -Mongoid 8.1 adds the ``:replace`` option to the ``#upsert`` method. This option -is ``false`` by default. - -In Mongoid 8 and earlier, and in Mongoid 8.1 when passing ``replace: true`` -(the default) the upserted document will overwrite the current document in the -database if it exists. Consider the following example: - -.. code:: ruby - - existing = Player.create!(name: "Juan Soto", age: 23, team: "WAS") - - player = Player.new(name: "Juan Soto", team: "SD") - player.id = existing.id - player.upsert # :replace defaults to true in 8.1 - - p Player.find(existing.id) - # => - -As you can see, the value for the ``:age`` field was dropped, because the -upsert replaced the entire document instead of just updating it. If we take the -same example and set ``:replace`` to ``false``, however: - -.. code:: ruby - - player.upsert(replace: false) - - p Player.find(existing.id) - # => - -This time, the value for the ``:age`` field is maintained. - -.. note:: - - The default for the ``:replace`` option will be changed to ``false`` in - Mongoid 9.0, therefore it is recommended to explicitly specify this option - while using ``#upsert`` in 8.1 for easier upgradability. - - -Allow Hash Assignment to ``embedded_in`` ----------------------------------------- - -Mongoid 8.1 allows the assignment of a hash to an ``embedded_in`` association. -On assignment, the hash will be coerced into a document of the class of the -association that it is being assigned to. This functionality already exists -for ``embeds_one`` and ``embeds_many`` associations. Consider the following -example: - -.. code:: ruby - - class Band - include Mongoid::Document - field :name, type: String - embeds_many :albums - end - - class Album - include Mongoid::Document - embedded_in :band - end - - album = Album.new - album.band = { name: "Death Cab For Cutie" } - p album.band - # => - -See the section on :ref:`Hash Assignment on Embedded Associations ` -for more details - - -Added ``none_of`` Query Method ------------------------------- - -With the addition of ``none_of``, Mongoid 8.1 allows queries to exclude -conditions in bulk. The emitted query will encapsulate the specified -criteria in a ``$nor`` operation. For example: - -.. code:: ruby - - class Building - include Mongoid::Document - field :city, type: String - field :height, type: Integer - field :purpose, type: String - field :occupancy, type: Integer - end - - Building.where(city: 'Portland'). - none_of(:height.lt => 100, - :purpose => 'apartment', - :occupancy.gt => 2500) - -This would query all buildings in Portland, excluding apartments, buildings less than -100 units tall, and buildings with an occupancy greater than 2500 people. - - -Added ``Mongoid::Config.immutable_ids`` ---------------------------------------- - -Coming in Mongoid 9.0, the ``_id`` field will be immutable in both top-level -and embedded documents. This addresses some inconsistency in how mutations -to the ``_id`` field are treated currently. To prepare for this potentially -breaking change, the ``Mongoid::Config.immutable_ids`` flag has been added. It -defaults to ``false``, preserving the existing behavior, but you may set it to -``true`` to prepare your apps for Mongoid 9.0. When this is set to ``true``, -attempts to mutate the ``_id`` of a document will raise an exception. - -.. code:: ruby - - # The default in Mongoid 8.1 - Mongoid::Config.immutable_ids = false - - # The default in Mongoid 9.0 - Mongoid::Config.immutable_ids = true diff --git a/docs/release-notes/mongoid-9.0.txt b/docs/release-notes/mongoid-9.0.txt deleted file mode 100644 index f6870f8eae..0000000000 --- a/docs/release-notes/mongoid-9.0.txt +++ /dev/null @@ -1,598 +0,0 @@ -.. _mongoid-9.0: - -*********** -Mongoid 9.0 -*********** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -This page describes significant changes and improvements in Mongoid 9.0. -The complete list of releases is available `on GitHub -`_ and `in JIRA -`_; -please consult GitHub releases for detailed release notes and JIRA for -the complete list of issues fixed in each release, including bug fixes. - -Railsmdb for Mongoid --------------------- - -To coincide with the release of Mongoid 9.0 a new command-line utility for creating, -updating, managing, and maintaining Rails applications has also -been made 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: - -.. code-block:: sh - - $ bin/railsmdb generate model person - -This will create a new model at ``app/models/person.rb``: - -.. code-block:: ruby - - class Person - include Mongoid::Document - include Mongoid::Timestamp - end - -You can specify the fields of the model as well: - -.. code-block:: ruby - - # 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: - -.. code-block:: ruby - - # bin/railsmdb generate model student --parent=person - - class Student < Person - include Mongoid::Timestamp - end - -And if you need to store your models in a different collection than can be -inferred from the model name, you can specify ``--collection``: - -.. code-block:: ruby - - # 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 `GitHub Repository `_. - - -Support for Ruby 2.6 and JRuby 9.3 Dropped -------------------------------------------- - -Mongoid 9 requires Ruby 2.7 or newer or JRuby 9.4. Earlier Ruby and JRuby -versions are not supported. - - -Support for Rails 5 Dropped ------------------------------ - -Mongoid 9 requires Rails 6.0 or newer. Earlier Rails versions are not supported. - - -Deprecated class ``Mongoid::Errors::InvalidStorageParent`` removed ------------------------------------------------------------------- - -The deprecated class ``Mongoid::Errors::InvalidStorageParent`` has been removed. - - -``around_*`` callbacks for embedded documents are now ignored -------------------------------------------------------------- - -Mongoid 8.x and older allows user to define ``around_*`` callbacks for embedded -documents. Starting from 9.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 10.0. - - -Deprecated options removed --------------------------- - -**Breaking change:** The following config options are removed in Mongoid 9.0. -Please ensure you have removed all references to these from your app. -If you were using ``config.load_defaults 8.1`` prior to 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 7.5 and -prior has been dropped (you must use a minimum of version 8.0.) - - -Deprecated functionality removed --------------------------------- - -**Breaking change:** The following deprecated functionality is now removed: - -- The ``Mongoid::QueryCache`` module has been removed. Please replace any usages 1-for-1 with ``Mongo::QueryCache``. - The method ``Mongoid::QueryCache#clear_cache`` should be replaced with ``Mongo::QueryCache#clear``. - All other methods and submodules are identically named. Refer to the `driver query cache documentation - `_ for more details. -- ``Object#blank_criteria?`` method is removed (was previously deprecated.) -- ``Document#as_json :compact`` option is removed. Please call ```#compact`` on the - returned ``Hash`` object instead. -- The deprecated class ``Mongoid::Errors::InvalidStorageParent`` has been removed. - - -``touch`` method now clears changed state ------------------------------------------ - -In Mongoid 8.x and older ``touch`` method leaves models in the changed state: - -.. code-block:: ruby - - # Mongoid 8.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 from 9.0 Mongoid now correctly clears changed state after using ``touch`` -method. - -.. code-block:: ruby - - # Mongoid 9.0 behaviour - 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 ActiveRecord: - -.. code-block:: ruby - - Band.transaction do - Band.create(title: 'Led Zeppelin') - end - - band = Band.create(title: 'Deep Purple') - band.transaction do - band.active = false - band.save! - end - -Please consult :ref:`transactions documentation ` for more details. - -Embedded Documents Always Use Parent Persistence Context --------------------------------------------------------- - -Mongoid 8.x and older allows user to specify persistence context for an -embedded document (using ``store_in`` macro). In Mongoid 9.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 skip Mongoid's type coercion logic -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. - -.. code-block:: ruby - - 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. - -.. code-block:: ruby - - 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. - -.. code-block:: ruby - - 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 always using 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. - -.. code-block:: ruby - - 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 now default to ``touch: true`` ------------------------------------------------------------ - -Updating an embedded subdocument will now automatically touch the parent, -unless you explicitly set ``touch: false`` on the relation: - -.. code-block:: ruby - - 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 8.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 9.0 flips the default of this flag from ``true`` => ``false``. - -This means that, by default, Mongoid 9 will update the existing document and -will not replace it. - - -The immutability of the ``_id`` field is now enforced ------------------------------------------------------ - -Prior to Mongoid 9.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. As of 9.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``. - -.. code-block:: ruby - - Mongoid::Config.immutable_ids = true - -When set to false, the older, inconsistent behavior is restored. - - -Support 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``. - -.. code-block:: ruby - - 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. - -.. code-block:: ruby - - 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: - -.. code-block:: ruby - - 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 with 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: - -.. code-block:: ruby - - 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: - -.. code-block:: bash - - # 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 - - -``Time.configured`` has been removed ------------------------------------- - -``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``. - -.. code-block:: ruby - - # 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: - -.. code-block:: ruby - - Time.zone = 'UTC' - -This will set the time zone to UTC. You can see all available time zone names -by running the following command: - -.. code-block:: bash - - $ ruby -ractive_support/values/time_zone \ - -e 'puts ActiveSupport::TimeZone::MAPPING.keys' - - -Records now remember the persistence context in which they were loaded/created ------------------------------------------------------------------------------- - -Consider the following code: - -.. code-block:: ruby - - record = Model.with(collection: 'other_collection') { Model.first } - record.update(field: 'value') - -Prior to Mongoid 9.0, this could would silently fail 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 9.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-9.0) behavior, you can enable it with the following -flag: - -.. code-block:: ruby - - Mongoid.legacy_persistence_context_behavior = true - -This flag defaults to false in Mongoid 9. - - -Bug Fixes and Improvements --------------------------- - -This section will be for smaller bug fixes and improvements: - -- The ``.unscoped`` method now also clears scopes declared using ``.with_scope`` - `MONGOID-5214 `_. -- When evolving a ``String`` to a ``BigDecimal`` (i.e. when querying a - ``BigDecimal`` field with a ``String`` object), if the - ``map_big_decimal_to_decimal128`` flag set to true, the conversion will - return a ``BSON::Decimal128`` and not a ``String`` - `MONGOID-5484 `_. -- Created new error ``Mongoid::Errors::InvalidEstimatedCountCriteria`` for - when calling ``estimated_document_count`` on a document class with a - default scope - `MONGOID-4960 `_. -- Mongoid now uses primary reads for validations in all cases - `MONGOID-5150 `_. -- Added support for symbol keys in localized field translation hashes - `MONGOID-5334 `_. -- Added index wildcard option - `MONGOID-5388 `_. -- With the ``map_big_decimal_to_decimal128`` flag set to false, ``demongoizing`` - a non-numeric, non-string value that implements ``:to_d`` will return a string - rather than a ``BigDecimal`` - `MONGOID-5507 `_. -- Added support for serializing and deserializing BSON::ObjectId values - when passed as ActiveJob arguments - `MONGOID-5611 `_. diff --git a/docs/release-notes/upgrading.txt b/docs/release-notes/upgrading.txt deleted file mode 100644 index db27af622a..0000000000 --- a/docs/release-notes/upgrading.txt +++ /dev/null @@ -1,119 +0,0 @@ -.. _upgrading: - -***************** -Upgrading Mongoid -***************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -Mongoid provides a stable upgrade path for users migrate to new versions. - - -Versioning -========== - -Each Mongoid release has a version number in ``major.minor.patch`` format. Beginning in -Mongoid 7.4, Mongoid uses `Semantic Versioning (SemVer) `_, which -typically means: - -- Breaking changes, enablement of new functionality, and removal of deprecated - functionality will only be done in major version releases. - -- New functionality will be added using feature flags, which must be enabled via - an opt-in configuration change. These feature flags may be added in either major - or minor releases. - -- Functionality may be marked as deprecated in either major or minor releases, but will - not be removed until the next major release, at the earliest. - -- Patch version releases will contain only non-breaking fixes and security updates. - -.. warning:: - - Mongoid 7.3 and prior do not strictly adhere to SemVer and may contain breaking changes even - in minor version releases. Users should exercise additional caution when upgrading to - these versions. - - -How to Upgrade Mongoid -====================== - -Before you Upgrade ------------------- - -- *Test Coverage:* The best way to be sure that your application still works after upgrading - is to have good test coverage before you start the process. - -- *Upgrade Ruby and Rails:* See `"Upgrading Ruby on Rails" `_ - for more information - - -Upgrading Mongoid ------------------ - -The following outlines our recommended procedure to upgrade to a new Mongoid version: - -1. Upgrade to each minor version individually. - - For example, if you are upgrading from Mongoid 7.4 to 8.1, we recommend you follow this - procedure for the latest patch version of each minor version, e.g. first to 7.5.x, - then to 8.0.x, and finally to 8.1.x. - -2. Before upgrading, ensure you have ``load_defaults`` set to your current version. - - If you haven't yet enabled the latest behavior on your current version, you should do so - prior to upgrading. - -3. Review the :ref:`Release Notes ` carefully when upgrading. - -4. Test your app on the new version. - - Your app should be tested and released "as-is" on the new Mongoid version _without_ adjusting - ``load_defaults`` or any feature flags. - -5. Once Step 4 is confirmed to be stable, set ``load_defaults`` to the new version to enable - new functionality. Also fix any deprecation warnings at this time. - - You may also enable new functionalities one-by-one using feature flags. - - -Load Defaults and Feature Flags -------------------------------- - -When a feature flag is introduced, it will have a default value that preserves -the previous (legacy) functionality. At this time, users are encouraged to manually -set the flag to its new value in order to try out the new functionality. - -In the next major version release, the flag's default value will be flipped to -enable the new functionality. At this time, the flag itself will be marked deprecated. -Finally, the deprecated flag will be removed from the config entirely in a subsequent -major version release. - -Feature flags are added as a convenience to facilitate upgrading, but are not intended -to be supported in perpetuity. - - -Deprecation Policy ------------------- - -Mongoid may deprecate features, functionality, methods, constants, etc. from -time to time. To do so, Mongoid may take one or more of the following actions: - -- Mark the relevant code ``@deprecated`` in a code comment. - -- Add a log warning if the deprecated functionality is used. - -- Inform of the deprecation in the :ref:`Release Notes `. - -Mongoid may then remove the deprecated functionality in the next major version -release. - -Methods which are marked ``@api private`` may be removed without deprecation, -even if such methods are ``public`` in Ruby. diff --git a/docs/schema-configuration.txt b/docs/schema-configuration.txt deleted file mode 100644 index 091c4bcf6b..0000000000 --- a/docs/schema-configuration.txt +++ /dev/null @@ -1,31 +0,0 @@ -.. _schema-configuration: - -******************** -Schema Configuration -******************** - -.. default-domain:: mongodb - -.. toctree:: - :titlesonly: - - reference/fields - reference/inheritance - reference/associations - reference/validation - reference/collection-configuration - reference/indexes - reference/sharding - -Overview --------- - -See the following sections to learn how to configure a schema with Mongoid: - -- :ref:`Field Definition ` -- :ref:`Inheritance ` -- :ref:`Associations ` -- :ref:`Validation ` -- :ref:`Collection Configuration ` -- :ref:`Index Management ` -- :ref:`Sharding Management ` \ No newline at end of file diff --git a/docs/tutorials.txt b/docs/tutorials.txt deleted file mode 100644 index 5c03cb901c..0000000000 --- a/docs/tutorials.txt +++ /dev/null @@ -1,29 +0,0 @@ -.. _tutorials: - -********* -Tutorials -********* - -.. default-domain:: mongodb - -.. toctree:: - :titlesonly: - - tutorials/getting-started-sinatra - tutorials/getting-started-rails7 - tutorials/getting-started-rails6 - tutorials/documents - tutorials/common-errors - tutorials/automatic-encryption - -Overview --------- - -See the following sections to learn more about working with Mongoid: - -- :ref:`Getting Started (Sinatra) ` -- :ref:`Getting Started (Rails 7) ` -- :ref:`Getting Started (Rails 6) ` -- :ref:`Documents ` -- :ref:`Common Errors ` -- :ref:`Automatic Client-Side Field Level Encryption ` \ No newline at end of file diff --git a/docs/tutorials/automatic-encryption.txt b/docs/tutorials/automatic-encryption.txt deleted file mode 100644 index 62e68c27da..0000000000 --- a/docs/tutorials/automatic-encryption.txt +++ /dev/null @@ -1,439 +0,0 @@ -.. _automatic-encryption: - -******************************************** -Automatic Client-Side Field Level Encryption -******************************************** - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -Since version 4.2 MongoDB supports `Client-Side Field Level Encryption -(CSFLE) `_. This is a feature -that enables you to encrypt data in your application before you send it over the -network to MongoDB. With CSFLE enabled, no MongoDB product has access to your -data in an unencrypted form. - -You can set up CSFLE using the following mechanisms: - -* `Automatic Encryption `_: - Enables you to perform encrypted read and write operations without you having - to write code to specify how to encrypt fields. -* `Explicit Encryption `_: - Enables you to perform encrypted read and write operations through your - MongoDB driver's encryption library. You must specify the logic for encryption - with this library throughout your application. - -Starting with version 9.0, Mongoid supports CSFLE's Automatic Encryption -feature. This tutorial walks you through the process of setting up and using -CSFLE in Mongoid. - -.. note:: - This tutorial does not cover all CSLFE features. - You can find more information about MongoDB CSFLE in - `the server documentation. `_ - -.. note:: - If you want to use explicit FLE, please follow `the Ruby driver documentation. - `_ - - -Installation -============ - -You can find the detailed description of how to install the necessary -dependencies in `the driver documentation. `_ - -Note the version of the Ruby driver being used in your application and select -the appropriate steps below. - -Install ``libmongocrypt`` -~~~~~~~~~~~~~~~~~~~~~~~~~ - -This can be done one of two ways. - -* Add the `libmongocrypt-helper gem `_ to - your ``Gemfile`` or -* Download the ``libmongocrypt`` `release archive `_, - extract the version that matches your operating system, and set the - ``LIBMONGOCRYPT_PATH`` environment variable accordingly. - -Install the automatic encryption shared library (Ruby driver 2.19+) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you use the Ruby driver version 2.19 and above, the automatic encryption -shared library should be installed by following the instructions on the -:manual:`Automatic Encryption Shared Library for Queryable Encryption -` -page in the Server manual. - -The steps required are as follows: - -1. Navigate to the `MongoDB Download Center `_ -2. From the Version dropdown, select ``x.y.z (current)`` (the latest current version). -3. In the Platform dropdown, select your platform. -4. In the Package dropdown, select ``crypt_shared``. -5. Click Download. - -Once extracted, ensure the full path to the library is configured within your -``mongoid.yml`` as follows: - -.. code-block:: yaml - - development: - clients: - default: - options: - auto_encryption_options: - extra_options: - crypt_shared_lib_path: '/path/to/mongo_crypt_v1.so' - -Install the ``mongocryptd`` (Ruby driver 2.18 or older) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you are using an older version of the Ruby driver ``mongocryptd`` will -need to be installed manually. ``mongocryptd`` comes pre-packaged with -enterprise builds of the MongoDB server (versions 4.2 and newer). -For installation instructions, see the `MongoDB manual `_. - -Add ``ffi`` to your Gemfile -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The MongoDB Ruby driver uses the `ffi gem `_ to call -functions from ``libmongocrypt``. As this gem is not a dependency of -the driver, it will need to be manually added to your ``Gemfile``: - -.. code-block:: ruby - - gem 'ffi' - -Create a Customer Master Key -============================ - -A Customer Master Key (CMK) is used to encrypt Data Encryption Keys. -The easiest way is to use a locally stored 96-bytes key. You can generate such -a key using the following Ruby code: - -.. code-block:: ruby - - require 'securerandom' - - SecureRandom.hex(48) # => "f54ab...." - -Later in this tutorial we assume that the Customer Master Key is -available from the ``CUSTOMER_MASTER_KEY`` environment variable. - -.. warning:: - - Using a local master key is insecure. It is recommended that you use a remote - Key Management Service to create and store your master key. To do so, follow - steps of the `"Set up a Remote Master Key" `_ - in the MongoDB Client-Side Encryption documentation. - - For more information about creating a master key, see the - `Create a Customer Master Key `_ - section of the MongoDB manual. - -Configure Clients -================= - -Automatic CSFLE requires some additional configuration for the MongoDB client. -Assuming that your application has just one ``default`` client, you need to -add the following to your ``mongoid.yml``: - -.. code-block:: yaml - - development: - clients: - default: - uri: mongodb+srv://user:pass@yourcluster.mongodb.net/blog_development?retryWrites=true&w=majority - options: - auto_encryption_options: # This key enables automatic encryption - key_vault_namespace: 'encryption.__keyVault' # Database and collection to store data keys - kms_providers: # Tells the driver where to obtain master keys - local: # We use the local key in this tutorial - key: "<%= ENV['CUSTOMER_MASTER_KEY'] %>" # Key that we generated earlier - extra_options: - crypt_shared_lib_path: '/path/to/mongo_crypt_v1.so' # Only if you use the library - - -Create a Data Encryption Key -============================ - -A Data Encryption Key (DEK) is the key you use to encrypt the fields in your -MongoDB documents. You store your Data Encryption Key in your Key Vault -collection encrypted with your CMK. - -To create a DEK in Mongoid you can use the -``db:mongoid:encryption:create_data_key`` ``Rake`` task: - -.. code-block:: sh - - % rake db:mongoid:encryption:create_data_key - Created data key with id: 'KImyywsTQWi1+cFYIHdtlA==' for kms provider: 'local' in key vault: 'encryption.__keyVault'. - -You can create multiple DEKs, if necessary. - -.. code-block:: sh - - % rake db:mongoid:encryption:create_data_key - Created data key with id: 'Vxr5m+5cQISjDOruzZgE0w==' for kms provider: 'local' in key vault: 'encryption.__keyVault'. - -You can also provide an alternate name for the DEK. This allows you to reference -the DEK by name when configuring encryption for your fields. It also allows you -to dynamically assign a DEK to a field at runtime. - -.. code-block:: sh - - % rake db:mongoid:encryption:create_data_key -- --key-alt-name=my_data_key - Created data key with id: 'yjF8hKmKQsqGeFGXlB9Sow==' with key alt name: 'my_data_key' for kms provider: 'local' in key vault: 'encryption.__keyVault'. - - -Configure Encryption Schema -=========================== - -Now we can tell Mongoid what should be encrypted: - -.. code-block:: ruby - - class Patient - include Mongoid::Document - include Mongoid::Timestamps - - # Tells Mongoid what DEK should be used to encrypt fields of the document - # and its embedded documents. - encrypt_with key_id: 'KImyywsTQWi1+cFYIHdtlA==' - - # This field is not encrypted. - field :category, type: String - - # This field is encrypted using AEAD_AES_256_CBC_HMAC_SHA_512-Random - # algorithm. - field :passport_id, type: String, encrypt: { - deterministic: false - } - # This field is encrypted using AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic - # algorithm. - field :blood_type, type: String, encrypt: { - deterministic: true - } - # This field is encrypted using AEAD_AES_256_CBC_HMAC_SHA_512-Random - # algorithm and using a different data key. - field :ssn, type: Integer, encrypt: { - deterministic: false, key_id: 'Vxr5m+5cQISjDOruzZgE0w==' - } - - embeds_one :insurance - end - - class Insurance - include Mongoid::Document - include Mongoid::Timestamps - - field :insurer, type: String - - # This field is encrypted using AEAD_AES_256_CBC_HMAC_SHA_512-Random - # algorithm using the key which alternate name is stored in the - # policy_number_key field. - field :policy_number, type: Integer, encrypt: { - deterministic: false, - key_name_field: :policy_number_key - } - - embedded_in :patient - end - -.. note:: - If you are developing a Rails application, it is recommended to set - ``preload_models`` to ``true`` in ``mongoid.yml``. This will ensure that - Mongoid loads all models before the application starts, and the encryption - schema is configured before any data is read or written. - -Known Limitations -~~~~~~~~~~~~~~~~~ - -* MongoDB CSFLE has some limitations that are described on the - :manual:`CSFLE Limitations ` - page in the Server manual. These limitations also apply to Mongoid. -* Mongoid does not support encryption of ``embeds_many`` relations. -* If you use ``:key_name_field`` option, the field must be encrypted using - non-deterministic algorithm. To encrypt your field deterministically, you must - specify ``:key_id`` option instead. - -Working with Data -================= - -Automatic CSFLE usage is transparent in many situations. - -.. note:: - In code examples below we assume that there is a variable ``unencrypted_client`` - that is a ``MongoClient`` connected to the same database but without encryption. - We use this client to demonstrate what is actually persisted in the database. - -Documents can be created as usual, fields will be encrypted and decrypted -according to the configuration: - -.. code-block:: ruby - - Patient.create!( - category: 'ER', - passport_id: '123456', - blood_type: 'AB+', - ssn: 98765, - insurance: Insurance.new(insurer: 'TK', policy_number: 123456, policy_number_key: 'my_data_key') - ) - - # Fields are encrypted in the database - unencrypted_client['patients'].find.first - # => - # {"_id"=>BSON::ObjectId('6446a1d046ebfd701f9f4292'), - # "category"=>"ER", - # "passport_id"=>, - # "blood_type"=>, - # "ssn"=>, - # "insurance"=>{"_id"=>BSON::ObjectId('6446a1d046ebfd701f9f4293'), "insurer"=>"TK", "policy_number"=>}, "policy_number_key"=>"my_data_key"} - -Fields encrypted using a deterministic algorithm can be queried. Only exact match -queries are supported. For more details please consult `the server documentation -`_. - -.. code-block:: ruby - - # We can find documents by deterministically encrypted fields. - Patient.where(blood_type: "AB+").to_a - # => [#] - -Encryption Key Management -========================= - -Customer Master Keys -~~~~~~~~~~~~~~~~~~~~ - -Your Customer Master Key is the key you use to encrypt your Data Encryption Keys. -MongoDB automatically encrypts Data Encryption Keys using the specified CMK -during Data Encryption Key creation. - -The CMK is the most sensitive key in CSFLE. If your CMK is compromised, all of -your encrypted data can be decrypted. - -.. important:: - Ensure you store your Customer Master Key (CMK) on a remote KMS. - - To learn more about why you should use a remote KMS, see `Reasons to Use a Remote KMS. `_ - - To view a list of all supported KMS providers, see the `KMS Providers `_ page. - -MongoDB CSFLE supports the following Key Management System (KMS) providers: - * `Amazon Web Services KMS `_ - * `Azure Key Vault `_ - * `Google Cloud Platform KMS `_ - * Any KMIP Compliant Key Management System - * Local Key Provider (for testing only) - -Data Encryption Keys -~~~~~~~~~~~~~~~~~~~~ - -Data Encryption Keys can be created using the -``db:mongoid:encryption:create_data_key`` ``Rake`` task. By default they are -stored on the same cluster as the database. -However, it might be a good idea to store the keys separately. This can be -done by specifying a key vault client in ``mongoid.yml``: - -.. code-block:: yaml - - development: - clients: - key_vault: - uri: mongodb+srv://user:pass@anothercluster.mongodb.net/blog_development?retryWrites=true&w=majority - default: - uri: mongodb+srv://user:pass@yourcluster.mongodb.net/blog_development?retryWrites=true&w=majority - options: - auto_encryption_options: - key_vault_client: :key_vault # Client to connect to key vault - # ... - -Encryption Keys Rotation -~~~~~~~~~~~~~~~~~~~~~~~~ - -You can rotate encryption keys using the ``rewrap_many_data_key`` method -of the Ruby driver. This method automatically decrypts multiple data encryption -keys and re-encrypts them using a specified CMK. It then updates -the rotated keys in the key vault collection. This method allows you to rotate -encryption keys based on two optional arguments: - -* A filter used to specify which keys to rotate. If no data key matches the - given filter, no keys will be rotated. Omit the filter to rotate all keys in - your key vault collection. -* An object that represents a new CMK. Omit this object to rotate the data - keys using their current CMKs. - -Here is an example of rotating keys using AWS KMS: - -.. code-block:: ruby - - # Create a key vault client - key_vault_client = Mongo::Client.new('mongodb+srv://user:pass@yourcluster.mongodb.net') - # Or, if you declared the key value client in mongoid.yml, use it - key_vault_client = Mongoid.client(:key_vault) - - # Create the encryption object - encryption = Mongo::ClientEncryption.new( - key_vault_client, - key_vault_namespace: 'encryption.__keyVault', - kms_providers: { - aws: { - "accessKeyId": "", - "secretAccessKey": "" - } - } - ) - - encryption.rewrap_many_data_key( - {}, # We want to rewrap all keys - { - provider: 'aws', - master_key: { - region: 'us-east-2', - key: 'arn:aws:kms:us-east-2:...' - } - } - ) - -Adding Automatic Encryption To Existing Project -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -MongoDB automatic CSFLE supports encryption in place. You can enable encryption -for your existing database, and will still able to read unencrypted data. -All data written to the database will be encrypted. However, as soon as the -encryption is enabled, all query operations will use encrypted data: - -.. code-block:: ruby - - # We assume that there are two documents in the database, one created without - # encryption enabled, and one with encryption. - - # We can still read both. - Patient.all.to_a - # => - # [#, - # #] - - # But when we query, we can see only the latter one. - Patient.where(blood_type: 'AB+').to_a - # => [#] - -If you want to encrypt the existing database, it can be achieved by reading -and writing back all data, even without any changes. If you decide to do so, -please keep the following in mind: - -* Validate the integrity of existing data for consistent fidelity. CSFLE is - type sensitive - for example you cannot store integers in a field that is - declared as ``String``. -* For strings, make sure that empty values are always empty strings or just - not set, but not ``nil`` (CSFLE doesn't support native ``null``). -* This operation requires application downtime. diff --git a/docs/tutorials/common-errors.txt b/docs/tutorials/common-errors.txt deleted file mode 100644 index 226e3b0e59..0000000000 --- a/docs/tutorials/common-errors.txt +++ /dev/null @@ -1,51 +0,0 @@ -.. _common-errors: - -************* -Common Errors -************* - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Mongoid/Moped Authentication Error: failed with error 13 -======================================================== - -If you are encountering the following error: - -.. code-block:: ruby - - Moped::Errors::OperationFailure: The operation: #1, :w=>1} - @fields=nil> - failed with error 13: "not authorized for insert on mongose_development.people" - - See https://github.com/mongodb/mongo/blob/master/docs/errors.md - for details about this error. - from /.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/bundler/gems/moped-10abbf3eac37/lib/moped/operation/read.rb:50:in `block in execute' - from /.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/bundler/gems/moped-10abbf3eac37/lib/moped/node.rb:594:in `[]' - from /.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/bundler/gems/moped-10abbf3eac37/lib/moped/node.rb:594:in `block (2 levels) in flush' - from /.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/bundler/gems/moped-10abbf3eac37/lib/moped/node.rb:593:in `map' - from /.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/bundler/gems/moped-10abbf3eac37/lib/moped/node.rb:593:in `block in flush' - from /.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/bundler/gems/moped-10abbf3eac37/lib/moped/node.rb:617:in `block in logging' - from /.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/notifications.rb:164:in `block in instrument' - from /.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0/lib/active_support/notifications/instrumenter.rb:20:in `instrumen - -This error is caused by Moped, a Ruby driver that is no longer in use by -Mongoid. Upgrading to Mongoid 5+ should fix this issue. - -You can find more information about this issue here: -`MONGOID-4067 `_. - diff --git a/docs/tutorials/documents.txt b/docs/tutorials/documents.txt deleted file mode 100644 index 2bd87f3015..0000000000 --- a/docs/tutorials/documents.txt +++ /dev/null @@ -1,18 +0,0 @@ -.. _documents: - -********* -Documents -********* - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Documents are the core objects in Mongoid and any object that is to be persisted to the -database must include ``Mongoid::Document``. The representation of a Document in MongoDB -is a BSON object that is very similar to a Ruby hash or JSON object. Documents can be stored -in their own collections in the database, or can be embedded in other Documents n levels deep. diff --git a/docs/tutorials/getting-started-rails6.txt b/docs/tutorials/getting-started-rails6.txt deleted file mode 100644 index 4b1128f8cf..0000000000 --- a/docs/tutorials/getting-started-rails6.txt +++ /dev/null @@ -1,558 +0,0 @@ -.. _getting-started-6: - -************************* -Getting Started (Rails 6) -************************* - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -.. note:: - - This tutorial is for Ruby on Rails 6. If this is not the version you're using choose - the appropriate tutorial for your Rails version from the navigation menu. - -New Application -=============== - -This section shows how to create a new Ruby on Rails application using Mongoid -for data access. The application will be similar to the blog application -described in the `Ruby on Rails Getting Started -`_ -guide, however using Mongoid instead of ActiveRecord as the database adapter. - -The complete source code for this application can be found in the -`mongoid-demo GitHub repository -`_. - -.. note:: - - This guide assumes basic familiarity with Ruby on Rails. - To learn more about Ruby on Rails, please refer to its `Getting Started - guide `_ or - other Rails guides. - - -Install ``rails`` ------------------ - -We will use a Rails generator to create the application skeleton. -In order to do so, the first step is to install the ``rails`` gem: - -.. code-block:: sh - - gem install rails -v '~> 6.0' - - -Create New Application ----------------------- - -Use the ``rails`` command to create the application skeleton, as follows: - -.. code-block:: sh - - rails new blog --skip-active-record --skip-bundle - cd blog - -.. note:: - - You may receive a warning like this: - - .. code-block:: sh - - Could not find gem 'puma (~> 3.11)' in any of the gem sources listed in your Gemfile. - Run `bundle install` to install missing gems. - - Disregard it as we will be taking care of gem installation - in a moment. - -We pass ``--skip-active-record`` to request that ActiveRecord is not added -as a dependency, because we will be using Mongoid instead. Additionally -we pass ``--skip-bundle`` because we'll be modifying the ``Gemfile`` to -add the ``mongoid`` dependency. - -If you intend to test your application with RSpec, you can instruct the -generator to omit default Rails test setup by passing ``--skip-test`` -and ``--skip-system-test`` options: - -.. code-block:: sh - - rails new blog --skip-bundle --skip-active-record --skip-test --skip-system-test - cd blog - - -Create Git Repo ---------------- - -While not required, we recommend creating a Git repository for your application: - -.. code-block:: sh - - git init . - git add . - git commit - -Commit your changes as you are following this tutorial. - - -Add Mongoid ------------ - -1. Modify the ``Gemfile`` to add a reference to the -`mongoid `_ gem: - -.. code-block:: ruby - :caption: Gemfile - - gem 'mongoid' - -.. note:: - - Mongoid 7.0.5 or higher is required to use Rails 6.0. - -2. Install gem dependencies: - -.. code-block:: sh - - bundle install - -3. Generate the default Mongoid configuration: - -.. code-block:: sh - - bin/rails g mongoid:config - -This generator will create the ``config/mongoid.yml`` configuration file -(used to configure the connection to the MongoDB deployment) and the -``config/initializers/mongoid.rb`` initializer file (which may be used for -other Mongoid-related configuration). Note that as we are not using -ActiveRecord we will not have a ``database.yml`` file. - - -.. _run-locally: - -Run MongoDB Locally -------------------- - -The configuration created in the previous step is suitable when -a MongoDB server is running locally. If you do not already have a -local MongoDB server, `download and install MongoDB -`_. - -While the generated ``mongoid.yml`` will work without modifications, -we recommend reducing the server selection timeout for development. -With this change, the uncommented lines of ``mongoid.yml`` should look -like this: - -.. code-block:: none - - development: - clients: - default: - database: blog_development - hosts: - - localhost:27017 - options: - server_selection_timeout: 1 - - -.. _use-atlas: - -Use MongoDB Atlas ------------------ - -Instead of downloading, installing and running MongoDB locally, you can create -a free MongoDB Atlas account and create a `free MongoDB cluster in Atlas -`_. -Once the cluster is created, follow the instructions in `connect to the cluster -page `_ -to obtain the URI. Use the *Ruby driver 2.5 or later* format. - -Paste the URI into the ``config/mongoid.yml`` file, and comment out the -hosts that are defined. We recommend setting the server selection timeout to 5 -seconds for development environment when using Atlas. - -The uncommented contents of ``config/mongoid.yml`` should look like this: - -.. code-block:: yaml - - development: - clients: - default: - uri: mongodb+srv://user:pass@yourcluster.mongodb.net/blog_development?retryWrites=true&w=majority - options: - server_selection_timeout: 5 - - -Other Rails Dependencies ------------------------- - -If this is the first Rails application you are creating, you may need to -install Node.js on your computer. This can be done via your operating system -packages or by `downloading a binary `_. - -Next, if you do not have Yarn installed, `follow its installation instructions -`_. - -Finally, install webpacker: - -.. code-block:: sh - - rails webpacker:install - - -Run Application ---------------- - -You can now start the application server by running: - -.. code-block:: sh - - rails s - -Access the application by navigating to `localhost:3000 -`_. - - -Add Posts ---------- - -Using the standard Rails scaffolding, Mongoid can generate the necessary -model, controller and view files for our blog so that we can quickly begin -creating blog posts: - -.. code-block:: sh - - bin/rails g scaffold Post title:string body:text - -Navigate to `localhost:3000/posts `_ -to create posts and see the posts that have already been created. - -.. image:: ../img/rails-new-blog.png - :alt: Screenshot of the new blog - - -Add Comments ------------- - -To make our application more interactive, let's add the ability for users to -add comments to our posts. - -Create the ``Comment`` model: - -.. code-block:: sh - - bin/rails g scaffold Comment name:string message:string post:belongs_to - -Open the ``Post`` model file, ``app/models/post.rb``, and add a ``has_many`` -association for the comments: - -.. code-block:: ruby - :caption: app/models/post.rb - - class Post - include Mongoid::Document - - field :title, type: String - field :body, type: String - - has_many :comments, dependent: :destroy - end - -.. note:: - *The following is only required if using a version of Mongoid < 7.0.8 or 7.1.2 (see* - `MONGOID-4885 `_ *for details)* - - Open the ``Comment`` model file, ``app/models/comment.rb``, and change the - generated ``embedded_in`` association to ``belongs_to``: - - .. code-block:: ruby - :caption: app/models/comment.rb - - class Comment - include Mongoid::Document - - field :name, type: String - field :message, type: String - - belongs_to :post - end - -Open the post show view file, ``app/views/posts/show.html.erb``, and add -a section rendering existing comments and prompting to leave a new comment: - -.. code-block:: html - :caption: app/views/posts/show.html.erb - -
-
-

- <%= @post.comments.count %> Comments -

- <%= render @post.comments %> -
-
-

Leave a reply

- <%= render partial: 'comments/form', locals: { comment: @post.comments.build } %> -
-
-
- -Open the comment form file and change the type of field for ``:message`` -from ``text_field`` to ``text_area``, as well as the type of field for -``:post_id`` from ``text_field`` to ``hidden_field``. The result -should look like this: - -.. code-block:: html - :caption: app/views/comments/_form.html.erb - - <%= form_with(model: comment, local: true) do |form| %> - <% if comment.errors.any? %> -
-

<%= pluralize(comment.errors.count, "error") %> prohibited this comment from being saved:

- -
    - <% comment.errors.full_messages.each do |message| %> -
  • <%= message %>
  • - <% end %> -
-
- <% end %> - -
- <%= form.label :name %> - <%= form.text_field :name %> -
- -
- <%= form.label :message %> - <%= form.text_area :message %> -
- -
- <%= form.hidden_field :post_id %> -
- -
- <%= form.submit %> -
- <% end %> - -Create a partial for the comment view, ``app/views/comments/_comment.html.erb`` -with the following contents: - -.. code-block:: html - :caption: app/views/comments/_comment.html.erb - -

- <%= comment.name %>: - <%= comment.message %> -
- <%= link_to 'Delete', [comment], - method: :delete, - class: "button is-danger", - data: { confirm: 'Are you sure?' } %> -

- -You should now be able to leave comments for the posts: - -.. image:: ../img/rails-blog-new-comment.png - :alt: Screenshot of the blog with a new comment being added - - -Existing Application -==================== - -Follow these steps to switch an existing Ruby on Rails application to use -Mongoid instead of ActiveRecord. - -Dependencies ------------- - -Remove or comment out any RDBMS libraries like ``sqlite``, ``pg`` etc. -mentioned in ``Gemfile``, and add ``mongoid``: - -.. code-block:: ruby - :caption: Gemfile - - gem 'mongoid' - -.. note:: - - Mongoid 7.0.5 or higher is required to use Rails 6.0. - -Install gem dependencies: - -.. code-block:: sh - - bundle install - -Loaded Frameworks ------------------ - -Examine ``config/application.rb``. If it is requiring all components of Rails -via ``require 'rails/all'``, change it to require individual frameworks: - -.. code-block:: ruby - :caption: config/application.rb - - # Remove or comment out - #require "rails/all" - - # Add this require instead of "rails/all": - require "rails" - - # Pick the frameworks you want: - require "active_model/railtie" - require "active_job/railtie" - require "action_controller/railtie" - require "action_mailer/railtie" - # require "action_mailbox/engine" - # require "action_text/engine" - require "action_view/railtie" - require "action_cable/engine" - require "sprockets/railtie" - require "rails/test_unit/railtie" - - # Remove or comment out ActiveRecord and ActiveStorage: - # require "active_record/railtie" - # require "active_storage/engine" - -.. note:: - - At this time ActiveStorage requires ActiveRecord and is not usable with - Mongoid. - -ActiveRecord Configuration --------------------------- - -Review all configuration files (``config/application.rb``, -``config/environments/{development,production.test}.rb``) and remove or -comment out any references to ``config.active_record`` and -``config.active_storage``. - -Stop Spring ------------ - -If your application is using Spring, which is the default on Rails 6, -Spring must be stopped after changing dependencies or configuration. - -.. code-block:: sh - - ./bin/spring stop - -.. note:: - - Sometimes running ``./bin/spring stop`` claims to stop Spring, but does - not. Verify that all Spring processes are terminated before proceeding. - -.. note:: - - Sometimes Spring tries to load ActiveRecord even when the application - contains no ActiveRecord references. If this happens, add an ActiveRecord - adapter dependency such as ``sqlite3`` to your ``Gemfile`` so that - ActiveRecord may be completely loaded or remove Spring from your - application. - -Mongoid Configuration ---------------------- - -Generate the default Mongoid configuration: - -.. code-block:: sh - - bin/rails g mongoid:config - -This generator will create the ``config/mongoid.yml`` configuration file -(used to configure the connection to the MongoDB deployment) and the -``config/initializers/mongoid.rb`` initializer file (which may be used for -other Mongoid-related configuration). In general, it is recommended to use -``mongoid.yml`` for all Mongoid configuration. - -Review the sections :ref:`Run MongoDB Locally ` and -:ref:`Use MongoDB Atlas ` to decide how you would like to deploy -MongoDB, and adjust Mongoid configuration (``config/mongoid.yml``) to match. - -Adjust Models -------------- - -If your application already has models, these will need to be changed when -migrating from ActiveRecord to Mongoid. - -ActiveRecord models derive from ``ApplicationRecord`` and do not have -column definitions. Mongoid models generally have no superclass but must -include ``Mongoid::Document``, and usually define the fields explicitly -(but :ref:`dynamic fields ` may also be used instead of -explicit field definitions). - -For example, a bare-bones Post model may look like this in ActiveRecord: - -.. code-block:: ruby - :caption: app/models/post.rb - - class Post < ApplicationRecord - has_many :comments, dependent: :destroy - end - -The same model may look like this in Mongoid: - -.. code-block:: ruby - :caption: app/models/post.rb - - class Post - include Mongoid::Document - - field :title, type: String - field :body, type: String - - has_many :comments, dependent: :destroy - end - -Or like this with dynamic fields: - -.. code-block:: ruby - :caption: app/models/post.rb - - class Post - include Mongoid::Document - include Mongoid::Attributes::Dynamic - - has_many :comments, dependent: :destroy - end - -Mongoid does not utilize ActiveRecord migrations, since MongoDB does not -require a schema to be defined prior to storing data. - -Data Migration --------------- - -If you already have data in a relational database that you would like to -transfer to MongoDB, you will need to perform a data migration. As noted -above, no schema migration is necessary because MongoDB does not require -a predefined schema to store the data. - -The migration tools are often specific to the data being migrated because, -even though Mongoid supports a superset of ActiveRecord associations, -the way that model references are stored in collections differs between -Mongoid and ActiveRecord. With that said, MongoDB has -some resources on migrating from an RDBMS to MongoDB such as the -`RDBMS to MongoDB Migration Guide `_ and -`Modernization Guide `_. - - -Rails API ---------- - -The process for creating a Rails API application with Mongoid is the same -as when creating a regular application, with the only change being the -``--api`` parameter to ``rails new``. Migrating a Rails API application to -Mongoid follows the same process described above for regular Rails applications. - -A complete Rails API application similar to the one described in this tutorial -can be found in `the mongoid-demo GitHub repository -`_. diff --git a/docs/tutorials/getting-started-rails7.txt b/docs/tutorials/getting-started-rails7.txt deleted file mode 100644 index b0805fbca4..0000000000 --- a/docs/tutorials/getting-started-rails7.txt +++ /dev/null @@ -1,470 +0,0 @@ -.. _getting-started-7: - -************************* -Getting Started (Rails 7) -************************* - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -.. note:: - - This tutorial is for Ruby on Rails 7. If this is not the version you're using choose - the appropriate tutorial for your Rails version from the navigation menu. - -New Application -=============== - -This section demonstrates how to create a new Ruby on Rails application using the Mongoid ODM. -By replacing Rails' default `ActiveRecord `_ -adapter with MongoDB's ORM-like library for data access we will create an application similar to the -blog application described in the `Ruby on Rails Getting Started -`_ guide. - -The complete source code for this application can be found in the -`mongoid-demo GitHub repository -`_. - -.. note:: - - This guide assumes basic familiarity with Ruby on Rails. - To learn more about Ruby on Rails, please refer to its `Getting Started - guide `_ or - other Rails guides. - - -Install ``rails`` ------------------ - -We will use a Rails generator to create the application skeleton. -In order to do so, the first step is to install the ``rails`` gem: - -.. code-block:: sh - - gem install rails -v '~> 7' - - -Create New Application ----------------------- - -Use the ``rails`` command to create the application skeleton, as follows: - -.. code-block:: sh - - rails new blog --skip-active-record - cd blog - -We pass ``--skip-active-record`` to request that ActiveRecord is not added -as a dependency, because we will be using Mongoid instead. - -Optionally Skip Tests -````````````````````` - -If you intend to test your application with `RSpec `_, you can instruct the -generator to omit the default Rails test setup by passing ``--skip-test`` -and ``--skip-system-test`` options: - -.. code-block:: sh - - rails new blog --skip-active-record --skip-test --skip-system-test - cd blog - -Setup Mongoid -------------- - -1. Modify the ``Gemfile`` to add a reference to the -`mongoid `_ gem: - -.. code-block:: ruby - :caption: Gemfile - - gem 'mongoid' - -2. Install gem dependencies: - -.. code-block:: sh - - bundle install - -3. Generate the default `Mongoid configuration `_: - -.. code-block:: sh - - bin/rails g mongoid:config - -This generator will create the ``config/mongoid.yml`` configuration file -(used to configure the connection to the MongoDB deployment) and the -``config/initializers/mongoid.rb`` initializer file (which may be used for -other Mongoid-related configuration). Note that as we are not using -ActiveRecord we will not have a ``database.yml`` file. - - -.. _configure-self-managed: - -Configure for Self Managed MongoDB -`````````````````````````````````` - -The configuration created in the previous step is suitable when -a MongoDB server is running locally. If you do not already have a -local MongoDB server, `download and install MongoDB -`_. - -While the generated ``mongoid.yml`` will work without modifications, -we recommend reducing the server selection timeout for development. -With this change, the uncommented lines of ``mongoid.yml`` should look -like this: - -.. code-block:: yaml - - development: - clients: - default: - database: blog_development - hosts: - - localhost:27017 - options: - server_selection_timeout: 1 - - -.. _configure-atlas: - -Configure for MongoDB Atlas -``````````````````````````` - -Instead of downloading, installing and running MongoDB locally, you can create -a free MongoDB Atlas account and create a `free MongoDB cluster in Atlas -`_. -Once the cluster is created, follow the instructions in `connect to the cluster -page `_ -to obtain the URI. Use the *Ruby driver 2.5 or later* format. - -Paste the URI into the ``config/mongoid.yml`` file, and comment out the -hosts that are defined. We recommend setting the server selection timeout to 5 -seconds for development environment when using Atlas. - -The uncommented contents of ``config/mongoid.yml`` should look like this: - -.. code-block:: yaml - - development: - clients: - default: - uri: mongodb+srv://user:pass@yourcluster.mongodb.net/blog_development?retryWrites=true&w=majority - options: - server_selection_timeout: 5 - -Run Application ---------------- - -You can now start the application server by running: - -.. code-block:: sh - - bin/rails s - -Access the application by navigating to `localhost:3000 -`_. - - -Add Posts ---------- - -Using the standard Rails scaffolding, Mongoid can generate the necessary -model, controller and view files for our blog so that we can quickly begin -creating blog posts: - -.. code-block:: sh - - bin/rails g scaffold Post title:string body:text - -Navigate to `localhost:3000/posts `_ -to create posts and see the posts that have already been created. - -.. image:: ../img/rails-new-blog.png - :alt: Screenshot of the new blog - - -Add Comments ------------- - -To make our application more interactive, let's add the ability for users to -add comments to our posts. - -Create the ``Comment`` model: - -.. code-block:: sh - - bin/rails g scaffold Comment name:string message:string post:belongs_to - -Open the ``Post`` model file, ``app/models/post.rb``, and add a ``has_many`` -association for the comments: - -.. code-block:: ruby - :caption: app/models/post.rb - - class Post - include Mongoid::Document - include Mongoid::Timestamps - field :title, type: String - field :body, type: String - - has_many :comments, dependent: :destroy - end - -Open ``app/views/posts/show.html.erb`` and add -a section rendering existing comments and prompting to leave a new comment: - -.. code-block:: erb - :caption: app/views/posts/show.html.erb - -
-
-

- <%= @post.comments.count %> Comments -

- <%= render @post.comments %> -
-
-

Leave a reply

- <%= render partial: 'comments/form', locals: { comment: @post.comments.build } %> -
-
-
- -Open ``app/views/comments/_form.html.erb`` and change the type of field for ``:message`` -from ``text_field`` to ``text_area``, as well as the type of field for -``:post_id`` from ``text_field`` to ``hidden_field``. The result -should look like this: - -.. code-block:: erb - :caption: app/views/comments/_form.html.erb - - <%= form_with(model: comment, local: true) do |form| %> - <% if comment.errors.any? %> -
-

<%= pluralize(comment.errors.count, "error") %> prohibited this comment from being saved:

- -
    - <% comment.errors.full_messages.each do |message| %> -
  • <%= message %>
  • - <% end %> -
-
- <% end %> - -
- <%= form.label :name %> - <%= form.text_field :name %> -
- -
- <%= form.label :message %> - <%= form.text_area :message %> -
- -
- <%= form.hidden_field :post_id %> -
- -
- <%= form.submit %> -
- <% end %> - -Next replace ``app/view/comments/_comment.html.erb`` with the following contents: - -.. code-block:: erb - :caption: app/views/comments/_comment.html.erb - -

- <%= comment.name %>: - <%= comment.message %> - <%= link_to 'Delete', [comment], - data: { - "turbo-method": :delete, - "turbo-confirm": 'Are you sure?' - } %> -

- - -You should now be able to leave comments for the posts: - -.. image:: ../img/rails-blog-new-comment.png - :alt: Screenshot of the blog with a new comment being added - - -Existing Application -==================== - -Mongoid can be easily added to an existing Rails application and run alongside other ActiveRecord -adapters. If this is your use case, updating dependencies and populating the configuration file will -allow you to start using MongoDB within your application. - -To switch an existing Ruby on Rails application to use Mongoid instead of ActiveRecord additional -configuration changes will be required, as described below. - -Dependencies ------------- - -First, the ``mongoid`` gem will need to be added your ``Gemfile``. - -.. code-block:: ruby - :caption: Gemfile - - gem 'mongoid' - -If Mongoid will be the **only** database adapter, remove or comment out any RDBMS libraries -like ``sqlite`` or ``pg`` mentioned in the ``Gemfile``. - -Install gem dependencies: - -.. code-block:: sh - - bundle install - -Mongoid Configuration ---------------------- - -Generate the default Mongoid configuration: - -.. code-block:: sh - - bin/rails g mongoid:config - -This generator will create the ``config/mongoid.yml`` configuration file -(used to configure the connection to the MongoDB deployment) and the -``config/initializers/mongoid.rb`` initializer file (which may be used for -other Mongoid-related configuration). In general, it is recommended to use -``mongoid.yml`` for all Mongoid configuration. - -Review the sections :ref:`Configure for Self Managed MongoDB ` -and :ref:`Configure for MongoDB Atlas ` to decide how you -would like to deploy MongoDB, and adjust the Mongoid configuration -(``config/mongoid.yml``) to match. - -Loaded Frameworks ------------------ - -Examine ``config/application.rb``. If it is requiring all components of Rails -via ``require 'rails/all'``, change it to require individual frameworks. To verify the contents of -``rails/all`` for your version see the `Github Repository -`_: - -.. code-block:: ruby - :caption: config/application.rb - - # Remove or comment out - #require "rails/all" - - # Add the following instead of "rails/all": - require "rails" - - # require "active_record/railtie" rescue LoadError - # require "active_storage/engine" rescue LoadError - require "action_controller/railtie" rescue LoadError - require "action_view/railtie" rescue LoadError - require "action_mailer/railtie" rescue LoadError - require "active_job/railtie" rescue LoadError - require "action_cable/engine" rescue LoadError - # require "action_mailbox/engine" rescue LoadError - # require "action_text/engine" rescue LoadError - require "rails/test_unit/railtie" rescue LoadError - -.. warning:: - - Due to their reliance on ActiveRecord, `ActionText `_, - `ActiveStorage `_ and - `ActionMailbox `_ cannot be used - with Mongoid. - -ActiveRecord Configuration --------------------------- - -Review all configuration files (``config/application.rb``, -``config/environments/{development,production.test}.rb``) and remove or -comment out any references to ``config.active_record`` and -``config.active_storage``. - -Adjust Models -------------- - -If your application already has models, these will need to be changed when -migrating from ActiveRecord to Mongoid. - -ActiveRecord models derive from ``ApplicationRecord`` and do not have -column definitions. Mongoid models generally have no superclass but must -include ``Mongoid::Document``, and usually define the fields explicitly -(but :ref:`dynamic fields ` may also be used instead of -explicit field definitions). - -For example, a bare-bones Post model may look like this in ActiveRecord: - -.. code-block:: ruby - :caption: app/models/post.rb - - class Post < ApplicationRecord - has_many :comments, dependent: :destroy - end - -The same model may look like this in Mongoid: - -.. code-block:: ruby - :caption: app/models/post.rb - - class Post - include Mongoid::Document - - field :title, type: String - field :body, type: String - - has_many :comments, dependent: :destroy - end - -Or like this with dynamic fields: - -.. code-block:: ruby - :caption: app/models/post.rb - - class Post - include Mongoid::Document - include Mongoid::Attributes::Dynamic - - has_many :comments, dependent: :destroy - end - -Mongoid does not utilize ActiveRecord migrations, since MongoDB does not -require a schema to be defined prior to storing data. - -Data Migration --------------- - -If you already have data in a relational database that you would like to -transfer to MongoDB, you will need to perform a data migration. As noted -above, no schema migration is necessary because MongoDB does not require -a predefined schema to store the data. - -The migration tools are often specific to the data being migrated because, -even though Mongoid supports a superset of ActiveRecord associations, -the way that model references are stored in collections differs between -Mongoid and ActiveRecord. With that said, MongoDB has -some resources on migrating from an RDBMS to MongoDB such as the -`RDBMS to MongoDB Migration Guide `_ and -`Modernization Guide `_. - - -Rails API ---------- - -The process for creating a Rails API application with Mongoid is the same -as when creating a regular application, with the only change being the -``--api`` parameter to ``rails new``. Migrating a Rails API application to -Mongoid follows the same process described above for regular Rails applications. - -A complete Rails API application similar to the one described in this tutorial -can be found in `the mongoid-demo GitHub repository -`_. diff --git a/docs/tutorials/getting-started-sinatra.txt b/docs/tutorials/getting-started-sinatra.txt deleted file mode 100644 index 832dd0d6d0..0000000000 --- a/docs/tutorials/getting-started-sinatra.txt +++ /dev/null @@ -1,220 +0,0 @@ -.. _getting-started-sinatra: - -************************* -Getting Started (Sinatra) -************************* - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -New Application -=============== - -This section shows how to create a new Sinatra application using Mongoid -for data access. The process is similar for other Ruby applications not -using Ruby on Rails. - -The complete source code for this application is available `in the -mongoid-demo GitHub repository -`_. - -Create Git Repo ---------------- - -While not required, we recommend creating a Git repository for your application: - -.. code-block:: sh - - git init blog - cd blog - -Commit your changes as you are following this tutorial. - - -Create Gemfile --------------- - -Create a file named ``Gemfile`` with the following contents: - -.. code-block:: ruby - - source 'https://rubygems.org' - - gem 'sinatra' - gem 'mongoid' - gem 'puma' - - -Install Dependencies --------------------- - -Run the following commands to install the dependencies: - -.. code-block:: sh - - gem install bundler - bundle install - -This command will generate a file named ``Gemfile.lock`` which we recommend -committing to your Git repository. - - -Run MongoDB Locally -------------------- - -To develop locally with MongoDB, `download and install MongoDB -`_. - -Once MongoDB is installed and running, create a file named ``config/mongoid.yml`` -pointing to your deployment. For example, if you launched a standalone -``mongod`` on the default port, the following contents would be appropriate: - -.. code-block:: none - - development: - clients: - default: - database: blog_development - hosts: - - localhost:27017 - options: - server_selection_timeout: 1 - - -Use MongoDB Atlas ------------------ - -Instead of downloading, installing and running MongoDB locally, you can create -a free MongoDB Atlas account and create a `free MongoDB cluster in Atlas -`_. -Once the cluster is created, follow the instructions in `connect to the cluster -page `_ -to obtain the URI. Use the *Ruby driver 2.5 or later* format. - -Create a file named ``config/mongoid.yml`` with the following -contents, replacing the URI with the actual URI for your cluster: - -.. code-block:: yaml - - development: - clients: - default: - uri: mongodb+srv://user:pass@yourcluster.mongodb.net/blog_development?retryWrites=true&w=majority - options: - server_selection_timeout: 5 - - - -Basic Application ------------------ - -Create a file named ``app.rb`` with the following contents. First, some -requires: - -.. code-block:: ruby - - require 'sinatra' - require 'mongoid' - -Load the Mongoid configuration file and configure Mongoid. This is done -automatically when Mongoid is used with Rails, but since we are using Mongoid -with Sinatra, we need to do this ourselves: - -.. code-block:: ruby - - Mongoid.load!(File.join(File.dirname(__FILE__), 'config', 'mongoid.yml')) - -Now we can define some models: - -.. code-block:: ruby - - class Post - include Mongoid::Document - - field :title, type: String - field :body, type: String - - has_many :comments - end - - class Comment - include Mongoid::Document - - field :name, type: String - field :message, type: String - - belongs_to :post - end - -... and add some routes: - -.. code-block:: ruby - - get '/posts' do - Post.all.to_json - end - - post '/posts' do - post = Post.create!(params[:post]) - post.to_json - end - - get '/posts/:post_id' do |post_id| - post = Post.find(post_id) - post.attributes.merge( - comments: post.comments, - ).to_json - end - - post '/posts/:post_id/comments' do |post_id| - post = Post.find(post_id) - comment = post.comments.create!(params[:comment]) - {}.to_json - end - - -Run Application -=============== - -Launch the application: - -.. code-block:: sh - - bundle exec ruby app.rb - -Try some requests via curl: - -.. code-block:: sh - - curl http://localhost:4567/posts - # => [] - - curl -d 'post[title]=hello&post[body]=hello+world' http://localhost:4567/posts - # => {"_id":{"$oid":"5d8151ec96fb4f0ed5a7a03f"},"body":"hello world","title":"hello"} - - curl http://localhost:4567/posts - # => [{"_id":{"_id":{"$oid":"5d8151ec96fb4f0ed5a7a03f"},"body":"hello world","title":"hello"}] - - curl -d 'comment[name]=David&comment[message]=I+like' http://localhost:4567/posts/5d8151ec96fb4f0ed5a7a03f/comments - # => {} - - curl http://localhost:4567/posts/5d8151ec96fb4f0ed5a7a03f - # => {"_id":{"$oid":"5d8151ec96fb4f0ed5a7a03f"},"title":"hello","body":"hello world","comments":[{"_id":{"$oid":"5d8157ac96fb4f20c5e45c4d"},"message":"I like","name":"David","post_id":{"$oid":"5d8151ec96fb4f0ed5a7a03f"}}]} - - -Existing Application -==================== - -To start using Mongoid in an existing Sinatra applications, the steps are -essentially the same as the one given above for a new application: - -1. Add the ``mongoid`` dependency to the ``Gemfile``. -2. Create a ``mongoid.yml`` configuration file. -3. Load the configuration file and configure Mongoid in the application. -4. Define Mongoid models. diff --git a/docs/working-with-data.txt b/docs/working-with-data.txt deleted file mode 100644 index 2b8b1e9141..0000000000 --- a/docs/working-with-data.txt +++ /dev/null @@ -1,37 +0,0 @@ -.. _working-with-data: - -***************** -Working With Data -***************** - -.. default-domain:: mongodb - -.. toctree:: - :titlesonly: - - reference/crud - reference/queries - reference/text-search - reference/aggregation - reference/map-reduce - reference/persistence-configuration - reference/nested-attributes - reference/callbacks - reference/sessions - reference/transactions - -Overview --------- - -See the following sections to learn more about working with data in Mongoid: - -- :ref:`CRUD Operations ` -- :ref:`Queries ` -- :ref:`Text Search ` -- :ref:`Aggregation Pipeline ` -- :ref:`Map/Reduce ` -- :ref:`Persistence Configuration ` -- :ref:`Nested Attributes ` -- :ref:`Callbacks ` -- :ref:`Sessions ` -- :ref:`Transactions ` \ No newline at end of file