Overview
In this guide, you can learn how to create and manage indexes by using the MongoDB Scala Driver.
Indexes support the efficient execution of queries in MongoDB. Without indexes, MongoDB must perform a collection scan, reading every document in a collection to find query matches. Collection scans can slow your application's performance. If an appropriate index exists for a query, MongoDB uses that index to limit the documents it inspects.
Indexes also enable the following capabilities:
Efficient sorting
Geospatial search
Tip
MongoDB also uses indexes when finding documents for update operations and delete operations. Certain stages in the aggregation pipeline also use indexes to improve performance.
Query Coverage and Performance
When you execute a query against MongoDB, your command can include the following elements:
Query criteria that specify fields and values you are looking for
Options that affect the query's execution, such as read concern
Projection criteria that specify the fields MongoDB returns (optional)
Sort criteria that specify the order documents are returned (optional)
When all the fields in the query, projection, and sort are in the same index, MongoDB returns results from the index. This process is called a covered query.
Important
Sort Order
Sort criteria must match or invert the order of the index.
Consider an index on the field name in ascending order (A-Z) and age in descending order (9-0):
name_1_age_-1
MongoDB uses this index when you sort your data by either:
nameascending,agedescendingnamedescending,ageascending
Specifying name and age both ascending or both descending requires an in-memory sort.
For more information about index coverage, see Query Optimization in the MongoDB Server manual.
Operational Considerations
The following guidelines describe how you can optimize the way your application uses indexes:
To improve query performance, build indexes on fields that appear often in your application's queries and operations that return sorted results.
Track index memory and disk usage for capacity planning, because each index that you add consumes disk space and memory when active.
Avoid adding indexes that you infrequently use. Note that when a write operation updates an indexed field, MongoDB updates the related index.
Since MongoDB supports dynamic schemas, applications can query against fields whose names cannot be known in advance or are arbitrary. MongoDB 4.2 introduced wildcard indexes to help support these queries. Wildcard indexes are not designed to replace workload-based index planning.
For more information on designing your data model and choosing indexes appropriate for your application, see the MongoDB server documentation on Indexing Strategies and Data Modeling and Indexes.
Sample Application
You can use the following sample application to test the code on this page. To use the sample application, perform the following steps:
Ensure you have the Scala driver installed in your project. See the Download and Install guide to learn more.
Copy the following code and paste it into a new
.scalafile.Copy a code example from this page and paste it on the specified lines in the file.
import org.mongodb.scala._ import org.mongodb.scala.model.SearchIndexModel import java.util.concurrent.TimeUnit import scala.concurrent.Await import scala.concurrent.duration.Duration import org.mongodb.scala.model.Indexes object SearchIndexes { def main(args: Array[String]): Unit = { // Create a new client and connect to the server val mongoClient = MongoClient("<connection string URI>") val database = mongoClient.getDatabase("<database name>") val collection = database.getCollection("<collection name>") // Start example code here // End example code here Thread.sleep(1000) mongoClient.close() } }
Sample Data
The examples in this guide use the movies collection in the sample_mflix database from the Atlas sample datasets. To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see Get Started with Atlas.
Index Types
MongoDB supports several different index types to support querying your data. The following sections describe the most common index types and provide sample code for creating each index type. For a full list of index types, see Indexes in the Server manual.
Single Field Indexes
Single field indexes are indexes with a reference to a single field within a collection's documents. They improve single field query and sort performance, and support TTL Indexes that automatically remove documents from a collection after a certain amount of time or at a specific clock time.
Note
The _id_ index is an example of a single field index. This index is automatically created on the _id field when a new collection is created.
The following example creates an ascending index on the specified field:
val index = Indexes.ascending("<field name>") val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
To run the following examples in this section, you must include the following import statements in your file:
import org.mongodb.scala._ import org.mongodb.scala.model.Indexes import org.mongodb.scala.model.IndexOptions._ import org.mongodb.scala.model.Filters._ import scala.concurrent.Await import scala.concurrent.duration._ import scala.util.{Failure, Success} import java.util.concurrent.TimeUnit
Use the createIndex() method to create a single field index. The following example creates an index in ascending order on the title field:
val index = Indexes.ascending("title") val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
You can verify that the index was created by using the listIndexes() method. You should see an index for title in the list, as shown in the following output:
collection.listIndexes().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"v": 2, "key": {"title": 1}, "name": "title_1"}
The following is an example of a query that is covered by the index created on the title field:
val filter = equal("title", "Sweethearts") collection.find(filter).first().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"_id":...,"plot":"A musical comedy duo...", "genres":["Musical"],...,"title":"Sweethearts",...}
Compound Indexes
Compound indexes hold references to multiple fields within a collection's documents, improving query and sort performance.
Tip
To learn more about index prefixes see the Index Prefixes entry in the MongoDB Server manual.
The following example creates a compound index on the two specified fields.
val index = Indexes.compoundIndex( Indexes.descending("<field name 1>"), Indexes.ascending("<field name 2>") ) val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
To run the following examples in this section, you must include the following import statements in your file:
import org.mongodb.scala._ import org.mongodb.scala.model.Indexes import org.mongodb.scala.model.IndexOptions._ import org.mongodb.scala.model.Filters._ import scala.concurrent.Await import scala.concurrent.duration._ import scala.util.{Failure, Success} import java.util.concurrent.TimeUnit
Use the createIndex() method to create a compound index. The following example creates an index in descending order on the runtime field and in ascending order on the year field:
val index = Indexes.compoundIndex(Indexes.descending("runtime"), Indexes.ascending("year")) val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
You can verify that the index was created by using the listIndexes() method. You should see an index for runtime and year in the list, as shown in the following output:
collection.listIndexes().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"v": 2, "key": {"runtime": -1, "year": 1}, "name": "runtime_-1_year_1"}
The following is an example of a query that is covered by the index created on the runtime and year fields:
val filter = and(gt("runtime", 80), gt("year", 1999)) collection.find(filter).first().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"_id":...,"runtime": 98,...,"title": "In the Mood for Love",...,"year": 2000,...}
Multikey Indexes
Multikey indexes are indexes that improve the performance of queries on array-valued fields. You can create a multikey index on a collection by using the createIndex() method and the same syntax that you use to create a single field index.
When creating a multikey index, you must specify the following details:
The fields on which to create the index
The sort order for each field (ascending or descending)
The following example creates a multikey index on the specified array-valued field:
val index = Indexes.ascending("<field name>") val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
To run the following examples in this section, you must include the following import statements in your file:
import org.mongodb.scala._ import org.mongodb.scala.model.Indexes import org.mongodb.scala.model.IndexOptions._ import org.mongodb.scala.model.Filters._ import scala.concurrent.Await import scala.concurrent.duration._ import scala.util.{Failure, Success} import java.util.concurrent.TimeUnit
Use the createIndex() method to create a multikey index. The following example creates an index in ascending order on the cast field:
val index = Indexes.ascending("cast") val observable = collection.createIndex(index) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
You can verify that the index was created by calling the listIndexes() method. You should see an index for cast in the list, as shown in the following output:
collection.listIndexes().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"v": 2, "key": {"cast": 1}, "name": "cast_1"}
The following is an example of a query that is covered by the index created on the cast field:
val filter = and(equal("cast", "Aamir Khan"), equal("cast", "Kajol")) collection.find(filter).first().subscribe((doc: Document) => println(doc.toJson()), (e: Throwable) => println(s"There was an error: $e"))
{"_id":...,"title":"Fanaa",...,"cast": ["Aamir Khan", "Kajol", "Rishi Kapoor", "Tabu"],...}
MongoDB Search and MongoDB Vector Search Indexes
MongoDB Search enables you to perform full-text searches on collections hosted on MongoDB Atlas. MongoDB Search indexes specify the behavior of the search and which fields to index.
MongoDB Vector Search enables you to perform semantic searches on vector embeddings stored in MongoDB. To learn more about MongoDB Vector Search, see the MongoDB Vector Search Overview.
You can call the following methods on a collection to manage your MongoDB Search and MongoDB Vector Search indexes:
createSearchIndex()createSearchIndexes()listSearchIndexes()updateSearchIndex()dropSearchIndex()
Note
The preceding index management methods run asynchronously and might return before confirming that they ran successfully. To determine the current status of the indexes, call the listSearchIndexes() method.
Create Search and Vector Search Indexes
You can use the createSearchIndex() and the createSearchIndexes() methods to create one or more MongoDB Search or MongoDB Vector Search indexes. The createSearchIndexes() method accepts a list of index definitions, which allows you to create multiple indexes in one call and specify the index type for each index.
The following code example shows how to create a MongoDB Search index:
val index = Document("mappings" -> Document("dynamic" -> true)) collection.createSearchIndex("<index name>", index) .subscribe((result: String) => ())
Use the createSearchIndexes() method to create multiple MongoDB Search or MongoDB Vector Search indexes.
The following code example shows how to create MongoDB Search and MongoDB Vector Search indexes in one call:
val searchIdxMdl = SearchIndexModel( Option("searchIdx"), Document("analyzer" -> "lucene.standard", "mappings" -> Document("dynamic" -> true)), Option(SearchIndexType.search()) ) val vectorSearchIdxMdl = SearchIndexModel( Option("vsIdx"), Document( "fields" -> List( Document("type" -> "vector", "path" -> "embeddings", "numDimensions" -> 1536, "similarity" -> "dotProduct") ) ), Option(SearchIndexType.vectorSearch()) ) collection.createSearchIndexes(List(searchIdxMdl, vectorSearchIdxMdl)) .subscribe((result: String) => ())
To learn more about the syntax used to define MongoDB Search indexes, see the Index Reference guide in the Atlas manual.
List Search Indexes
You can use the listSearchIndexes() method to return all MongoDB Search indexes in a collection.
The following code example shows how to print a list of the search indexes in a collection by subscribing to the Observable returned by the listSearchIndexes() method:
collection.listSearchIndexes() .subscribe((result: Document) => println(result.toJson()))
{"id": "...", "name": "<index name 1>", "type": "search", "status": "READY", "queryable": true, ... } {"id": "...", "name": "<index name 2>", "type": "search", "status": "READY", "queryable": true, ... }
Update a Search Index
You can use the updateSearchIndex() method to update a MongoDB Search index.
The following code shows how to update a search index:
val updateIndex = Document("mappings" -> Document("dynamic" -> false)) collection.updateSearchIndex("<index to update>", updateIndex) .subscribe((result: Unit) => ())
Delete a Search Index
You can use the dropSearchIndex() method to delete a MongoDB Search index.
Warning
Deleting Search Indexes and Clusters Is Irreversible
Deleting Search indexes and associated clusters is a permanent action. MongoDB doesn't provide support for recovering deleted Search indexes or data. Ensure that you have taken appropriate measures, such as creating backups, to avoid data loss before proceeding.
MongoDB doesn't support requests to recover deleted Search indexes or data. You are responsible for data integrity and configurations.
The following code shows how to delete a search index from a collection:
collection.dropSearchIndex("<index name>") .subscribe((result: Unit) => ())
Geospatial Indexes
The following example creates a 2dsphere index on the specified field that contains GeoJSON objects:
val observable = collection.createIndex(Indexes.geo2dsphere("<2d index>")) Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
For more information on 2dsphere indexes, see the 2dsphere Indexes guide in the MongoDB Server manual.
For more information about the GeoJSON type, see the GeoJSON Objects guide in the MongoDB Server manual.
Remove an Index
You can remove any unused index except the default unique index on the _id field.
The following example deletes an index with the specified name:
val observable = collection.dropIndex("<index name>") Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
API Documentation
To learn more about the methods or objects used in this guide, see the following API documentation: