MongoDB Indexing Tutorial

In this MongoDB tutorial we learn how to store small portions of document data for quick and easy querying.

What is indexing

When querying for documents, MongoDB must scan every document in a collection. This scan is inefficient and requires MongoDB to process a large amount of data.

Indexes store a small portion of document data in an easy-to-traverse form, allowing the lookup to be much quicker.

The index stores value(s) from a key, or set of keys, and orders by the value of the key in the index.

How to create an index

To create an index we use the db.collection.createIndex() method.

This function takes two arguments.

  • Key:order to choose which values to index and to specify an order of ascending (1) or descending (-1)
  • Options to modify the operation (optional)
Syntax:
db.collection.createIndex({ key : order })

For example, let’s say we want to create an index of the email addresses in the following documents.

Example:
db.users.insert([
    { "name" : "John", "age" : 33, "email" : "john@example.com" },
    { "name" : "Jane", "age" : 28, "email" : "jane@example.com" },
    { "name" : "Jack", "age" : 30, "email" : "jack@example.com" },
    { "name" : "Jill", "age" : 27, "email" : "jill@example.com" }
])

We would simply use the “email” key and set an order of either 1 (ascending) or -1 (descending).

Example:
db.users.createIndex({ "email" : 1 })

If the operation was successful it will return an OK status.

Output:
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

We are allowed to create indexes on multiple keys with different ordering.

Example:
db.users.createIndex({
    "name" : 1,
    "email" : -1
})

It’s also a good idea to let the operation perform in the background, when we have many documents, so that building an index does not block other database activities.

To do that we simply use the background:true option.

Example:
db.users.createIndex(
    { "name" : 1, "email" : -1 },
    { background : true }
)

How to see all indexes in a collection

To return all the indexes stored in a collection we use the db.collection.getIndexes() method.

Example:
db.users.getIndexes()

Apart from the default _id, we stored the “name” and “email” keys with ascending and descending order respectively, from the previous section above.

Output:
[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_"
    },
    {
        "v" : 2,
        "key" : {
            "name" : 1,
            "email" : -1
        },
        "name" : "name_1_email_-1"
    }
]

Our index is stored in the second element of the index array.

How to create a text index

MongoDB allows us to create text indexes to support search queries on string content.

Any key that has a string value, or any array that contains string elements, may be includes in text indexes. We can only have one text search index, but we can cover multiple fields with this single index.

The text index syntax replaces the first parameter of key:order with key:"text" .

Syntax:
db.users.createIndex({ key : "text" })

For example, let’s say we wanted to create text indexes of both the “name” and “email” keys.

Example:
db.users.createIndex({
    "name": "text",
    "email": "text"
})

If the operation was successful it will return an OK status.

Output:
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

How to search through a text index

If we want to search through a text index we have to use the $search and $text meta operators with the .find() method.

Syntax:
db.collection.find({
    $text: { $search: "words to search for" }
})

For example, if we want to search for “John” in the text index created in the previous section above.

Example:
db.users.find({
    $text: { $search: "John" }
})

Any document(s) that matched the query will be returned.

Output:
{ "_id" : ObjectId("5fad19c893eba2b50e266e1d"), "name" : "John", "age" : 33, "email" : "john@example.com" }

The search works just like a search in Google or Bing. If we use multiple words it will try to match them in the index.

For example, we have an index made up of the “name” and “email” keys, so if we include ‘example’ in the search term, it will return everything that contains “John” and “example”.

Example:
db.users.find({
    $text: { $search: "John example" }
})
Output:
{ "_id" : ObjectId("5fad19c893eba2b50e266e20"), "name" : "Jill", "age" : 27, "email" : "jill@example.com" }
{ "_id" : ObjectId("5fad19c893eba2b50e266e1f"), "name" : "Jack", "age" : 30, "email" : "jack@example.com" }
{ "_id" : ObjectId("5fad19c893eba2b50e266e1e"), "name" : "Jane", "age" : 28, "email" : "jane@example.com" }
{ "_id" : ObjectId("5fad19c893eba2b50e266e1d"), "name" : "John", "age" : 33, "email" : "john@example.com" }

Luckily, we can search for exact phrases by wrapping it in double quotes.

Note that these extra double quotes must be escaped with \, or the outer quotes must be single quotes.

Example:
db.users.find({
    $text: { $search: '"john@example"' }
})
Output:
{ "_id" : ObjectId("5fad19c893eba2b50e266e1d"), "name" : "John", "age" : 33, "email" : "john@example.com" }

How to delete indexes in a collection

If we want to delete a single index from a collection, we use the db.collection.dropIndex() method.

This method takes only one argument, which is the index to drop.

Note that we cannot delete the default _id index.

Syntax:
db.collection.dropIndex({ index_name })

For example, let’s say we want to drop the index we made in the previous section above.

We need to find the index name first to be able to specify it in the command. To do that let’s run the getIndexes() method.

Example:
db.users.getIndexes()

Which gives us the following output.

Output:
[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_"
    },
    {
        "v" : 2,
        "key" : {
            "name" : 1,
            "email" : -1
        },
        "name" : "name_1_email_-1"
    }
]

We’re looking for the auto-generated name, in this case it’s “name_1email-1”.

Now we can use that name to delete the index.

Example:
db.users.dropIndex("name_1_email_-1")

Note that we pass the name directly as an argument, it’s not inside an array so it doesn’t have the wrapping curly braces.

Output:
{ "nIndexesWas" : 2, "ok" : 1 }

We can also delete multiple indexes with the db.collection.dropIndexes() method.

In this case we would pass the names of the indexes we wanted to delete in a list.

Syntax:
db.collection.dropIndexes({ "autogenerated_name_1", "autogenerated_name_2" })