Mongodb Indexes
Mongodb Indexes
MongoDB - Indexing
Indexes support the efficient resolution of queries. Without indexes, MongoDB must scan
every document of a collection to select those documents that match the query statement.
This scan is highly inefficient and require MongoDB to process a large volume of data.
Indexes are special data structures, that store a small portion of the data set in an easy-to-
traverse form. The index stores the value of a specific field or set of fields, ordered by the
value of the field as specified in the index.
Indexes support the efficient execution of queries in MongoDB. Without indexes, MongoDB
must perform a collection scan, i.e. scan every document in a collection, to select those
documents that match the query statement. If an appropriate index exists for a query,
MongoDB can use the index to limit the number of documents it must inspect.
Indexes are special data structures [1] that store a small portion of the collection's data set in
an easy to traverse form. The index stores the value of a specific field or set of fields, ordered
by the value of the field. The ordering of the index entries supports efficient equality matches
and range-based query operations. In addition, MongoDB can return sorted results by using
the ordering in the index.
The concept of indexing is crucial for any database, and so for MongoDB also. Databases
having indexes make queries performance more efficient. When you have a collection with
thousands of documents and no indexing is done, your query will keep on finding certain
documents sequentially. This would require more time to find the documents. But if your
documents have indexes, MongoDB would restrict make it specific the number of documents
to be searched within your collection.
Creating an Index :
MongoDB provides a method called createIndex() that allows user to create an index.
Syntax –
db.COLLECTION_NAME.createIndex({KEY:1})
The key determines the field on the basis of which you want to create an index and 1 (or -1)
determines the order in which these indexes will be arranged(ascending or descending).
Example –
db.mycol.createIndex({“age”:1})
{
“createdCollectionAutomatically” : false,
“numIndexesBefore” : 1,
“numIndexesAfter” : 2,
“ok” : 1
}
1
The createIndex() method also has a number of optional parameters.
These include:
background (Boolean)
unique (Boolean)
name (string)
sparse (Boolean)
Drop an Index
In order to drop an index, MongoDB provides the dropIndex() method.
Syntax –
db.NAME_OF_COLLECTION.dropIndex({KEY:1})
The dropIndex() methods can only delete one index at a time. In order to delete (or
drop) multiple indexes from the collection, MongoDB provides the dropIndexes()
method that takes multiple indexes as its parameters.
Syntax –
db.NAME_OF_COLLECTION.dropIndexes({KEY1:1, KEY2, 1})
The dropIndex() methods can only delete one index at a time. In order to delete (or
drop) multiple indexes from the collection, MongoDB provides the dropIndexes()
method that takes multiple indexes as its parameters.
Get description of all indexes :
The getIndexes() method in MongoDB gives a description of all the indexes that exists in
the given collection.
Syntax –
db.NAME_OF_COLLECTION.getIndexes()
It will retrieve all the description of the indexes created within the collection.
In createIndex() method you can pass multiple fields, to create index on multiple
fields.
>db.mycol.createIndex({"title":1,"description":-1})
>
This method also accepts list of options (which are optional). Following is the list −
2
Creates a unique index so that the collection will not accept
insertion of documents where the index key or keys match an
unique Boolean
existing value in the index. Specify true to create a unique index.
The default value is false.
For a text index, the language that determines the list of stop
default_language string words and the rules for the stemmer and tokenizer. The default
value is English.
For a text index, specify the name of the field in the document
language_override string that contains, the language to override the default language. The
default value is language.
3
{
"ok" : 0,
"errmsg" : "can't find index with key: { title: 1.0 }",
"code" : 27,
"codeName" : "IndexNotFound"
}
4
"v" : 2,
"key" : {
"title" : 1,
"description" : -1
},
"name" : "title_1_description_-1",
"ns" : "test.mycol"
}
]
Types of Indexes in MongoDB
In MongoDB, the indexing is supported for a few types, and every type carries different
purposes. Following are the types of indexes supported:
1. Compound Index: This is a user-defined index supported in MongoDB where multiple
fields can be indexed. To create a compound index, the query is
db.collection.createIndex( { <fieldname1: 1/-1, fieldname2: 1/-1, … }). Here, the compound
index query is similar to a normal index query but with multiple fields.
2. Single Field Index: Simple user-defined index with a single field. This is the normal
indexing as we have seen earlier in the below example.
Query:
db.zips.createIndex({city:1})
Output:
3. MultiKey Indexing: Now this is one indexing that works on values stored in an array.
Here, for each element in an array, MongoDB creates an index.
Query:
db.test.createIndex( {grade:1} )
Output:
One of the advantages of these multi-key indexing is the efficiency in queries against these
array fields. And this indexing can be implemented on arrays with nested documents and
arrays containing scalar variables.
4. Text Indexing: For the purpose of searching the string content or an array of string, ina
collection, indexing over the test is supported in MongoDB.
5. Hashed Index: Using the hashes of the indexed fields’ values, Hashed Indexing in
MongoDB is achieved. MongoDB also supports sharding based on the hash. The aim is to
reduce the size of the index. Range queries are not supported here.
Query:
db.collectionname.createIndex( { name: "hashed" } )
Output:
Types of index
MongoDB provides different types of indexes that are used according to the data type or
queries. The indexes supported by MongoDB is are as follows:
1. Single field Index: A single field index means index on a single field of a document.
This index is helpful for fetching data in ascending as well as descending order.
Syntax:
db.students.createIndex({“<fieldName>” : <1 or -1>});
Here 1 represents the field is specified in ascending order and -1 for descending order.
Example:
db.students.createIndex({studentsId:1})
In this example we are creating a single index on studentsId field and the field is specified
in ascending order.
5
2. Compound Index: We can combine multiple fields for compound indexing and that will
help for searching or filtering documents in that way. Or in other words, the compound
index is an index where a single index structure holds multiple references.
Syntax:
db.<collection>.createIndex( { <field1>: <type>, <field2>: <type2>, … } )
Here, we can combine the required fields in this pattern. Also the value of these fields is
1(for ascending order) or -1(for descending order).
Note: Compound indexes may have a single hashed index field but a hashing function is
required by Hashed indexes to compute the hash of the value of the index field.
Example:
Here, we create a compound index on studentAge: 1, studentName:1
db.students.createIndex({studentAge: 1, studentName:1})
db.students.find().sort({"studentAge":1,"studentName":1}).pretty()
Here we are taking the sorting functionality based on “studentAge” followed by
“studentName” fields and hence in the below image, though there are 2 documents
matching for “studentAge = 25”, as studentName is an additional value given, as a second
document, studentName with value “Geek40” is displayed and after that only, as a third
document, studentName with value “GeeksForGeeksbest” is displayed. Hence, sometimes
6
there will be a need to create compound indexes when we want to have a closer level of
filtration.
3. Multikey Index: MongoDB uses the multikey indexes to index the values stored in
arrays. When we index a field that holds an array value then MongoDB automatically
creates a separate index of each and every value present in that array. Using these multikey
indexes we can easily find a document that contains an array by matching the items. In
MongoDB, you don’t need to explicitly specify the multikey index because MongoDB
automatically determines whether to create a multikey index if the indexed field contains an
array value.
Syntax:
db.<collection>.createIndex( { <field>: <type>} )
Here, the value of the field is 1(for ascending order) or -1(for descending order).
Example:
In the students collection, we have three documents that contains array fields.
7
Now we view the document that holds skillsets:[“Java”, “Android”]
db.students.find({skillsets:["Java", "Android"]}).pretty()
8
Now, on the execution of the below query, we get
db.industries.find(
{
location:
{$near:
{
$geometry:{type: "Point", coordinates:[-73.9667, 40.78]},
$minDistance:1000,
$maxDistance: 5000
}
}
}
}.pretty()
Here, the “$near” operator returns documents that are in the specified range of at least
1000 meters from and at most 5000 meters from the specified GeoJSON point, and hence
we are getting only Tidal Park output. Similar to $near, it can support for $nearSphere,
$geoWithin, $geoIntersects,$geoNear etc.,
5. Text Index: MongoDB supports query operations that perform a text search of string
content. Text index allows us to find the string content in the specified collection. It can
include any field that contains string content or an array of string items. A collection can
contain at most one text index. You are allowed to use text index in the compound index.
Syntax:
db.<collection>.createIndex( { <field>: “text”} )
We can give exact phrases also for searching by enclosing the search terms in double
quotes
db.<collectionname>.find( { $text: { $search: “\”<Exact search term>\”” } } )
As here enclosed in double quotes, the search results contain only exact searched data.
9
In case, if we want to exclude a few texts in our search term, then we can do as
db.<collectionname>.find( { $text: { $search: “<search terms> -<not required search
terms>” } } )
Prepending a – character makes the search text to get ignored and the rest of the text is
considered.
In the text search, the results are available in unsorted order. To make it available in sorted
order of relevance score, $meta textScore field is needed and sort on it. Example:
db.singers.find(
{ $text: { $search: "Annisten" } },
{ score: { $meta: "textScore" } }
).sort( { score: { $meta: "textScore" } } )
Example:
In accessories collection we create text index:
db.accessories.createIndex({name: "text", description: "text"})
6. Hash Index: To maintain the entries with hashes of the values of the indexed
field(mostly _id field in all collections), we use Hash Index. This kind of index is mainly
required in the even distribution of data via sharding. Hashed keys are helpful to partition
the data across the sharded cluster.
Syntax:
db.<collection>.createIndex( { _id: “hashed” } )
From Version 4.4 onwards, the compound Hashed Index is applicable
7. Wildcard Index: MongoDB supports creating indexes either on a field or set of fields
and if the set of fields are mentioned, it is called as Wildcard Index. Generally, the wildcard
index does not include _id field but if you what to include _id field in the wildcard index
then you have to define it explicitly. MongoDB allows you to create multiple wildcard
indexes in the given collection. Wildcard indexes support queries for unknown or arbitrary
fields.
Syntax:
To create a wild card index on the specified field:
db.<collection>.createIndex( { “field.$**”:1 } )
To create a wild card index on all the field:
db.<collection>.createIndex( { “$**”:1 } )
To create a wild card index on multiple specified fields:
db.<collection>.createIndex(
10
{ “$**”:1 },
{“wildcardProjection”:
{“field1”: 1, “field2”:2}
})
Example:
In book collection we create the wildcard index:
11
Index Properties
In addition to the numerous index types MongoDB supports, indexes can also have various
properties. The following documents detail the index properties that you can select when
building an index.
TTL Indexes
The TTL index is used for TTL collections, which expire data after a period of time.
Unique Indexes
A unique index causes MongoDB to reject all documents that contain a duplicate
value for the indexed field.
Partial Indexes
A partial index indexes only documents that meet specified filter criteria.
Case Insensitive Indexes
A case insensitive index disregards the case of the index key values.
Hidden Indexes
A hidden index is not visible to the query planner.
Sparse Indexes
A sparse index does not index documents that do not have the indexed field.
TTL Indexes
NOTE
TTL indexes are special single-field indexes that MongoDB can use to automatically remove
documents from a collection after a certain amount of time or at a specific clock time. Data
expiration is useful for certain types of information like machine generated event data, logs,
and session information that only need to persist in a database for a finite amount of time.
To create a TTL index, use the createIndex() method on a field whose value is either
a date or an array that contains date values, and specify the expireAfterSeconds option with
the desired TTL value in seconds.
Behavior
Expiration of Data
TTL indexes expire documents after the specified number of seconds has passed since the
indexed field value; i.e. the expiration threshold is the indexed field value plus the specified
number of seconds.
If the field is an array, and there are multiple date values in the index, MongoDB
uses lowest (i.e. earliest) date value in the array to calculate the expiration threshold.
12
If the indexed field in a document is not a date or an array that holds one or more date values,
the document will not expire.
If a document does not contain the indexed field, the document will not expire.
Delete Operations
A background thread in mongod reads the values in the index and removes
expired documents from the collection.
When the TTL thread is active, you will see delete operations in the output
of db.currentOp() or in the data collected by the database profiler.
The TTL index does not guarantee that expired data will be deleted immediately upon
expiration. There may be a delay between the time a document expires and the time that
MongoDB removes the document from the database.
The background task that removes expired documents runs every 60 seconds. As a result,
documents may remain in a collection during the period between the expiration of the
document and the running of the background task.
Replica Sets
On replica set members, the TTL background thread only deletes documents when a member
is in state primary. The TTL background thread is idle when a member is in
state secondary. Secondary members replicate deletion operations from the primary.
Restrictions
TTL indexes are a single-field indexes. Compound indexes do not support TTL and
ignore the expireAfterSeconds option.
The _id field does not support TTL indexes.
You cannot create a TTL index on a capped collection because MongoDB cannot
remove documents from a capped collection.
13
You cannot create a TTL index on a time series collection. Similar functionality is
provided through automatic removal on time series collections instead.
You cannot use createIndex() to change the value of expireAfterSeconds of an
existing index. Instead use the collMod database command in conjunction with
the index collection flag. Otherwise, to change the value of the option of an existing
index, you must drop the index first and recreate.
If a non-TTL single-field index already exists for a field, you cannot create a TTL
index on the same field since you cannot create indexes that have the same key
specification and differ only by the options. To change a non-TTL single-field index
to a TTL index, you must drop the index first and recreate with
the expireAfterSeconds option.
Unique Indexes
A unique index ensures that the indexed fields do not store duplicate values; i.e. enforces
uniqueness for the indexed fields. By default, MongoDB creates a unique index on
the _id field during the creation of a collection.
NOTE
New Internal Format
Starting in MongoDB 4.2, for featureCompatibilityVersion (fCV) of 4.2 (or greater),
MongoDB uses a new internal format for unique indexes that is incompatible with earlier
MongoDB versions. The new format applies to both existing unique indexes as well as newly
created/rebuilt unique indexes.
14
The created index enforces uniqueness for the combination of groupNumber, lastname,
and firstname values.
The unique index permits the insertion of the following documents into the collection since
the index enforces uniqueness for the combination of a.loc and a.qty values:
db.collection.insertMany( [
{ _id: 2, a: [ { loc: "A" }, { qty: 5 } ] },
{ _id: 3, a: [ { loc: "A", qty: 10 } ] }
])
TIP
See also:
Behavior
Restrictions
MongoDB cannot create a unique index on the specified index field(s) if the collection
already contains data that would violate the unique constraint for the index.
15
index key values for that document do not duplicate those of another document. In this case,
the repeated index entry is inserted into the index only once.
The unique index permits the insertion of the following document into the collection if no
other document in the collection has an index key value of { "a.loc": "B", "a.qty": null }.
db.collection.insertOne( { _id: 4, a: [ { loc: "B" }, { loc: "B" } ] } )
The unique index allows the insertion of a document without the field x if the collection does
not already contain a document missing the field x:
db.collection.insertOne( { y: 1 } )
However, the unique index errors on the insertion of a document without the field x if the
collection already contains a document missing the field x:
db.collection.insertOne( { z: 1 } )
The operation fails to insert the document because of the violation of the unique constraint on
the value of the field x:
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error index: test.collection.$a.b_1 dup key: { : null }"
}
})
TIP
See also:
Unique Partial Indexes
16
Unique Partial Indexes
New in version 3.2.
Partial indexes only index the documents in a collection that meet a specified filter
expression. If you specify both the partialFilterExpression and a unique constraint, the
unique constraint only applies to the documents that meet the filter expression.
A partial index with a unique constraint does not prevent the insertion of documents that do
not meet the unique constraint if the documents do not meet the filter criteria. For an
example, see Partial Index with Unique Constraint.
For a ranged sharded collection, only the following indexes can be unique:
IMPORTANT
For a to-be-sharded collection, you cannot shard the collection if the collection has
other unique indexes.
For an already-sharded collection, you cannot create unique indexes on other fields.
17
Unique and Sparse Index Creation
This example creates multiple indexes with the same key pattern and different sparse options:
db.scoreHistory.createIndex( { score : 1 }, { name: "unique_index", unique: true } )
db.scoreHistory.createIndex( { score : 1 }, { name: "unique_sparse_index", unique: true, sparse: true } )
This duplication in key patterns allows for adding a unique index to already indexed fields.
In this example:
Create a basic index with the key pattern { score : 1 } and insert three documents.
db.scoreHistory.createIndex( { score : 1 }, { name: "basic_index" } )
db.scoreHistory.insert( { score : 1 } )
db.scoreHistory.insert( { score : 2 } )
db.scoreHistory.insert( { score : 3 } )
Partial Indexes
New in version 3.2.
Partial indexes only index the documents in a collection that meet a specified filter
expression. By indexing a subset of the documents in a collection, partial indexes have lower
storage requirements and reduced performance costs for index creation and maintenance.
18
equality expressions (i.e. field: value or using the $eq operator),
$exists: true expression,
$gt, $gte, $lt, $lte expressions,
$type expressions,
$and operator at the top-level only
For example, the following operation creates a compound index that indexes only the
documents with a rating field greater than 5.
db.restaurants.createIndex(
{ cuisine: 1, name: 1 },
{ partialFilterExpression: { rating: { $gt: 5 } } }
)
Behavior
Query Coverage
MongoDB will not use the partial index for a query or sort operation if using the index results
in an incomplete result set.
To use the partial index, a query must contain the filter expression (or a modified filter
expression that specifies a subset of the filter expression) as part of its query condition.
The following query can use the index since the query predicate includes the
condition rating: { $gte: 8 } that matches a subset of documents matched by the index filter
expression rating: { $gt: 5 }:
db.restaurants.find( { cuisine: "Italian", rating: { $gte: 8 } } )
However, the following query cannot use the partial index on the cuisine field because using
the index results in an incomplete result set. Specifically, the query predicate includes the
condition rating: { $lt: 8 } while the index has the filter rating: { $gt: 5 }. That is, the query {
cuisine: "Italian", rating: { $lt: 8 } } matches more documents (e.g. an Italian restaurant with
a rating equal to 1) than are indexed.
db.restaurants.find( { cuisine: "Italian", rating: { $lt: 8 } } )
Similarly, the following query cannot use the partial index because the query predicate does
not include the filter expression and using the index would return an incomplete result set.
db.restaurants.find( { cuisine: "Italian" } )
19
Comparison with Sparse Indexes
Partial indexes are be preferred over sparse indexes. Partial indexes provide the following
benefits:
Sparse indexes select documents to index solely based on the existence of the indexed field,
or for compound indexes, the existence of the indexed fields.
Partial indexes determine the index entries based on the specified filter. The filter can include
fields other than the index keys and can specify conditions other than just an existence check.
For example, a partial index can implement the same behavior as a sparse index:
db.contacts.createIndex(
{ name: 1 },
{ partialFilterExpression: { name: { $exists: true } } }
)
This partial index supports the same queries as a sparse index on the name field.
However, a partial index can also specify filter expressions on fields other than the index key.
For example, the following operation creates a partial index, where the index is on
the name field but the filter expression is on the email field:
db.contacts.createIndex(
{ name: 1 },
{ partialFilterExpression: { email: { $exists: true } } }
)
For the query optimizer to choose this partial index, the query predicate must include a
condition on the name field as well as a non-null match on the email field.
For example, the following query can use the index because it includes both a condition on
the name field and a non-null match on the email field:
db.contacts.find( { name: "xyz", email: { $regex: /\.org$/ } } )
However, the following query cannot use the index because it includes a null match on
the email field, which is not permitted by the filter expression { email: { $exists: true } }:
db.contacts.find( { name: "xyz", email: { $exists: false } } )
Restrictions
In earlier versions of MongoDB, creating multiple partial indexes is not allowed when using
the same key pattern with different partialFilterExpressions.
20
You cannot specify both the partialFilterExpression option and the sparse option.
Examples
Then, the following query on the restaurants collection uses the partial index to return the
restaurants in the Bronx with rating.grade equal to A:
db.restaurants.find( { borough: "Bronx", 'rating.grade': "A" } )
However, the following query cannot use the partial index because the query expression does
not include the rating.grade field:
db.restaurants.find( { borough: "Bronx", cuisine: "Bakery" } )
21
Partial Index with Unique Constraint
Partial indexes only index the documents in a collection that meet a specified filter
expression. If you specify both the partialFilterExpression and a unique constraint, the
unique constraint only applies to the documents that meet the filter expression. A partial
index with a unique constraint does not prevent the insertion of documents that do not meet
the unique constraint if the documents do not meet the filter criteria.
The index prevents the insertion of the following documents since documents already exist
with the specified usernames and the age fields are greater than 21:
db.users.insertMany( [
{ username: "david", age: 27 },
{ username: "amanda", age: 25 },
{ username: "rajiv", age: 32 }
])
However, the following documents with duplicate usernames are allowed since the unique
constraint only applies to documents with age greater than or equal to 21.
db.users.insertMany( [
{ username: "david", age: 20 },
{ username: "amanda" },
{ username: "rajiv", age: null }
])
New in version 3.4.
Case insensitive indexes support queries that perform string comparisons without regard for
case.
Behavior
Using a case insensitive index does not affect the results of a query, but it can increase
performance; see Indexes for a detailed discussion of the costs and benefits of indexes.
To use an index that specifies a collation, query and sort operations must specify the same
collation as the index. If a collection has defined a collation, all queries and indexes inherit
that collation unless they explicitly specify a different collation.
Examples
The following example creates a collection with no default collation, then adds an index on
the type field with a case insensitive collation.
db.createCollection("fruit")
db.fruit.createIndex( { type: 1},
{ collation: { locale: 'en', strength: 2 } } )
23
Case Insensitive Indexes on Collections with a Default Collation
When you create a collection with a default collation, all the indexes you create subsequently
inherit that collation unless you specify a different collation. All queries which do not specify
a different collation also inherit the default collation.
The following example creates a collection called names with a default collation, then creates
an index on the first_name field.
db.createCollection("names", { collation: { locale: 'en_US', strength: 2 } } )
db.names.createIndex( { first_name: 1 } ) // inherits the default collation
Queries on this collection use the specified collation by default, and if possible use the index
as well.
db.names.find( { first_name: "betsy" } )
// inherits the default collation: { collation: { locale: 'en_US', strength: 2 } }
// finds three results
The above operation uses the collection's default collation and finds all three documents. It
uses the index on the first_name field for better performance.
The above operation finds only one document, because it uses a collation with
no strength value specified. It does not use the collection's default collation or the index.
Hidden Indexes
New in version 4.4.
Hidden indexes are not visible to the query planner and cannot be used to support a query.
By hiding an index from the planner, users can evaluate the potential impact of dropping an
index without actually dropping the index. If the impact is negative, the user can unhide the
index instead of having to recreate a dropped index.
24
Behavior
Apart from being hidden from the planner, hidden indexes behave like unhidden indexes; i.e.
If a hidden index is a unique index, the index still applies its unique constraint to the
documents.
If a hidden index is a TTL index, the index still expires documents.
Hidden indexes are included in listIndexes and db.collection.getIndexes() results.
Hidden indexes are updated upon write operations to the collection and continue to
consume disk space and memory. As such, they are included in various statistics
operations, such as db.collection.stats() and $indexStats.
Hiding an unhidden index or unhiding a hidden index resets its $indexStats. Hiding
an already hidden index or unhiding an already unhidden index does not reset
the $indexStats.
Restrictions
Examples
For example, the following operation creates a hidden ascending index on the borough field:
db.addresses.createIndex(
{ borough: 1 },
{ hidden: true }
);
27
Because indexes are fully maintained while hidden, the index is immediately available for use
once unhidden.
Sparse Indexes
Sparse indexes only contain entries for documents that have the indexed field, even if the
index field contains a null value. The index skips over any document that is missing the
indexed field. The index is "sparse" because it does not include all documents of a collection.
By contrast, non-sparse indexes contain all documents in a collection, storing null values for
those documents that do not contain the indexed field.
IMPORTANT
The index does not index documents that do not include the xmpp_id field.
NOTE
Do not confuse sparse indexes in MongoDB with block-level indexes in other databases.
Think of them as dense indexes with a specific filter.
Behavior
For example, the query { x: { $exists: false } } will not use a sparse index on the x field
unless explicitly hinted. See Sparse Index On A Collection Cannot Return Complete
Results for an example that details the behavior.
Changed in version 3.4.
If you include a hint() that specifies a sparse index when you perform a count() of all
documents in a collection (i.e. with an empty query predicate), the sparse index is used even
if the sparse index results in an incorrect count.
db.collection.insertOne( { _id: 1, y: 1 } );
db.collection.createIndex( { x: 1 }, { sparse: true } );
db.collection.find().hint( { x: 1 } ).count();
28
To obtain the correct count, do not hint() with a sparse index when performing a count of all
documents in a collection.
db.collection.find().count();
db.collection.createIndex( { y: 1 } );
db.collection.find().hint( { y: 1 } ).count();
sparse Compound Indexes
Sparse compound indexes that only contain ascending/descending index keys will index a
document as long as the document contains at least one of the keys.
For sparse compound indexes that contain text index keys along with ascending/descending
index keys, only the existence of the text index field(s) determine whether the index
references a document.
sparse and unique Properties
An index that is both sparse and unique prevents collection from having documents with
duplicate values for a field but allows multiple documents that omit the key.
Examples
Then, the following query on the scores collection uses the sparse index to return the
documents that have the score field less than ($lt) 90:
db.scores.find( { score: { $lt: 90 } } )
Because the document for the userid "newbie" does not contain the score field and thus does
not meet the query criteria, the query can use the sparse index to return the results:
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
29
Sparse Index On A Collection Cannot Return Complete Results
Consider a collection scores that contains the following documents:
{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
Because the document for the userid "newbie" does not contain the score field, the sparse
index does not contain an entry for that document.
Even though the sort is by the indexed field, MongoDB will not select the sparse index to
fulfill the query in order to return complete results:
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }
The use of the index results in the return of only those documents with the score field:
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
TIP
You could create an index with a unique constraint and sparse filter on the score field using
the following operation:
db.scores.createIndex( { score: 1 } , { sparse: true, unique: true } )
This index would permit the insertion of documents that had unique values for
the score field or did not include a score field. As such, given the existing documents in
the scores collection, the index permits the following insert operations:
db.scores.insertMany( [
{ "userid": "AAAAAAA", "score": 43 },
{ "userid": "BBBBBBB", "score": 34 },
{ "userid": "CCCCCCC" },
{ "userid": "DDDDDDD" }
30
])
However, the index would not permit the addition of the following documents since
documents already exists with score value of 82 and 90:
db.scores.insertMany( [
{ "userid": "AAAAAAA", "score": 82 },
{ "userid": "BBBBBBB", "score": 90 }
])
31