mongodb/mongoid

View on GitHub
docs/reference/indexes.txt

Summary

Maintainability
Test Coverage
.. _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 <configuration-options>`.

The ``background`` option has `no effect as of MongoDB 4.2
<https://www.mongodb.com/docs/manual/core/index-creation/#comparison-to-foreground-and-background-builds>`_.


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'