Docs Menu
Docs Home
/ / /
Java Sync Driver
/

Indexes

On this page

  • Overview
  • Query Coverage and Performance
  • Operational Considerations
  • Index Types
  • Single Field and Compound Indexes
  • Multikey Indexes (Indexes on Array Fields)
  • Atlas Search and Vector Search Indexes
  • Text Indexes
  • Geospatial Indexes
  • Unique Indexes
  • Wildcard Indexes
  • Clustered Indexes
  • Remove an Index
  • Remove an Index Using an Index Specification Document
  • Remove an Index Using a Name Field
  • Remove an Index Using a Wildcard Character

In this guide, you can learn how to use indexes with the MongoDB Java driver.

Indexes support the efficient execution of queries in MongoDB. Without indexes, MongoDB must scan every document in a collection (a collection scan) to find the documents that match each query. These collection scans are slow and can negatively affect the performance of your application. If an appropriate index exists for a query, MongoDB can use the index to limit the documents it must inspect.

Indexes also:

  • Allow efficient sorting

  • Enable special capabilities like geospatial search

  • Allow adding constraints to ensure a field value is unique

  • And more

Tip

Indexes are also used by update operations when finding the documents to update, delete operations when finding the documents to delete, and by certain stages in the aggregation pipeline.

When you execute a query against MongoDB, your command can include various 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 to specify the fields MongoDB returns (optional)

  • Sort criteria to specify the order of documents returned from MongoDB (optional)

When all the fields specified in the query, projection, and sort are in the same index, MongoDB returns results directly from the index, also 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:

  • name ascending, age descending

  • name descending, age ascending

Specifying a sort order of name and age ascending or name and age descending requires an in-memory sort.

For more information about how to ensure your index covers your query criteria and projection, see the MongoDB manual articles on query coverage.

To improve query performance, build indexes on fields that appear often in your application's queries and operations that return sorted results. Each index that you add consumes disk space and memory when active, so we recommend that you track index memory and disk usage for capacity planning. In addition, 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 about designing your data model and choosing indexes appropriate for your application, see the MongoDB Server Data Modeling and Indexes.

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.

Tip

The MongoDB Java Driver provides the Indexes class that includes static factory methods to create index specification documents for different MongoDB Index key types.

The following examples use the createIndex() method to create various indexes, and the following setup:

import com.mongodb.DuplicateKeyException;
import com.mongodb.MongoCommandException;
import com.mongodb.client.*;
import com.mongodb.client.model.IndexOptions;
import com.mongodb.client.model.Indexes;
import com.mongodb.client.model.Sorts;
import com.mongodb.client.model.geojson.Point;
import com.mongodb.client.model.geojson.Position;
import org.apache.log4j.BasicConfigurator;
import org.bson.Document;
import org.bson.conversions.Bson;
import static com.mongodb.client.model.Filters.*;
import static com.mongodb.client.model.Projections.*;
final String uri = "mongodb+srv://<atlas-uri>/<dbname>?retryWrites=true&w=majority";
mongoClient = MongoClients.create(uri);
database = mongoClient.getDatabase("sample_mflix");
collection = database.getCollection("movies");

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 index in ascending order on the title field:

String resultCreateIndex = collection.createIndex(Indexes.ascending("title"));
System.out.println(String.format("Index created: %s", resultCreateIndex));

The following is an example of a query that is covered by the index created in the preceding code snippet:

Bson filter = eq("title", "Batman");
Bson sort = Sorts.ascending("title");
Bson projection = fields(include("title"), excludeId());
FindIterable<Document> cursor = collection.find(filter).sort(sort).projection(projection);

For more information, see Single Field Indexes in the MongoDB Server manual.

Compound indexes hold references to multiple fields within a collection's documents, improving query and sort performance.

Tip

Read more about compound indexes, index prefixes, and sort order here.

The following example creates a compound index on the type and rated fields:

String resultCreateIndex = collection.createIndex(Indexes.ascending("type", "rated"));
System.out.println(String.format("Index created: %s", resultCreateIndex));

The following is an example of a query that is covered by the index created in the preceding code snippet:

Bson filter = and(eq("type", "movie"), eq("rated", "G"));
Bson sort = Sorts.ascending("type", "rated");
Bson projection = fields(include("type", "rated"), excludeId());
FindIterable<Document> cursor = collection.find(filter).sort(sort).projection(projection);

For more information, see Compound Indexes in the MongoDB Server manual.

Multikey indexes are indexes that improve performance for queries that specify a field with an index that contains an array value. You can define a multikey index using the same syntax as a single field or compound index.

The following example creates a compound, multikey index on the rated, genres (an array of Strings), and title fields:

String resultCreateIndex = collection.createIndex(Indexes.ascending("rated", "genres", "title"));
System.out.println(String.format("Index created: %s", resultCreateIndex));

The following is an example of a query that is covered by the index created in the preceding code snippet:

Bson filter = and(eq("genres", "Animation"), eq("rated", "G"));
Bson sort = Sorts.ascending("title");
Bson projection = fields(include("title", "rated"), excludeId());
FindIterable<Document> cursor = collection.find(filter).sort(sort).projection(projection);

Multikey indexes behave differently from other indexes in terms of query coverage, index bound computation, and sort behavior. To learn more about multikey indexes, including a discussion of their behavior and limitations, see the Multikey Indexes page in the MongoDB manual.

You can programmatically manage your Atlas Search and Atlas Vector Search indexes by using the Java driver.

The Atlas Search feature enables you to perform full-text searches on collections hosted on MongoDB Atlas. To learn more about MongoDB Atlas Search, see the Atlas Search Indexes documentation.

Atlas Vector Search enables you to perform semantic searches on vector embeddings stored in MongoDB Atlas. To learn more about Atlas Vector Search, see the Atlas Vector Search section in the Aggregates Builder guide.

You can call the following methods on a collection to manage your Atlas Search and Vector Search indexes:

  • createSearchIndex() (valid for Atlas Search indexes only)

  • createSearchIndexes()

  • listSearchIndexes()

  • updateSearchIndex()

  • dropSearchIndex()

Note

The Atlas Search Index management methods run asynchronously. The driver methods can return before confirming that they ran successfully. To determine the current status of the indexes, call the listSearchIndexes() method.

The following sections provide code examples that demonstrate how to use each of the preceding methods.

You can use the createSearchIndex() method to create an Atlas Search index. You cannot use this method to create a Vector Search index.

The following code example shows how to create an Atlas Search index:

Document searchIdx = new Document("mappings",
new Document("dynamic", true));
collection.createSearchIndex("myIndex", searchIdx);

You can use the createSearchIndexes() method to create multiple Atlas Search indexes or one or more Vector Search indexes. You must create and pass a SearchIndexModel instance for each index.

The following code example shows how to create Search and Vector Search indexes in one call:

SearchIndexModel searchIdxMdl = new SearchIndexModel(
"searchIdx",
new Document("analyzer", "lucene.standard").append(
"mappings", new Document("dynamic", true)),
SearchIndexType.search()
);
SearchIndexModel vectorSearchIdxMdl = new SearchIndexModel(
"vsIdx",
new Document(
"fields",
Arrays.asList(
new Document("type", "vector")
.append("path", "embeddings")
.append("numDimensions", 1536)
.append("similarity", "dotProduct")
)
),
SearchIndexType.vectorSearch()
);
collection.createSearchIndexes(
Arrays.asList(searchIdxMdl, vectorSearchIdxMdl)
);

You can use the listSearchIndexes() method to return the Atlas Search indexes of a collection.

The following code example shows how to print a list of the search indexes of a collection:

try (MongoCursor<Document> resultsCursor = collection.listSearchIndexes().iterator()) {
while (resultsCursor.hasNext()) {
System.out.println(resultsCursor.next());
}
}

You can use the updateSearchIndex() method to update an Atlas Search index.

The following code shows how to update a search index:

collection.updateSearchIndex("myIndex",
new Document("analyzer", "lucene.simple").append(
"mappings",
new Document("dynamic", false)
.append("fields",
new Document("title",
new Document("type", "string")))
)
);

You can use the dropSearchIndex() method to remove an Atlas Search index.

The following code shows how to delete a search index from a collection:

collection.dropSearchIndex("myIndex");

Text indexes support text search queries on string content. These indexes can include any field whose value is a string or an array of string elements. MongoDB supports text search for various languages. You can specify the default language as an option when creating the index.

Tip

MongoDB offers an improved full-text search solution, Atlas Search. To learn more about Atlas Search indexes and how to use them, see the Atlas Search and Vector Search Indexes section of this guide.

The following example creates a text index on the plot field:

try {
String resultCreateIndex = collection.createIndex(Indexes.text("plot"));
System.out.println(String.format("Index created: %s", resultCreateIndex));
// Prints a message if a text index already exists with a different configuration
} catch (MongoCommandException e) {
if (e.getErrorCodeName().equals("IndexOptionsConflict"))
System.out.println("there's an existing text index with different options");
}

The following is an example of a query that uses the index created in the preceding code snippet. Note that the sort is omitted because text indexes do not contain sort order.

Bson filter = text("java coffee shop");
Bson projection = fields(include("fullplot"), excludeId());
FindIterable<Document> cursor = collection.find(filter).projection(projection);

A collection can only contain one text index. If you want to create a text index for multiple text fields, you must create a compound index. A text search runs on all the text fields within the compound index.

The following snippet creates a compound text index for the title and genre fields:

collection.createIndex(Indexes.compoundIndex(Indexes.text("title"), Indexes.text("genre")));

For more information, see the following Server Manual Entries:

MongoDB supports queries of geospatial coordinate data using 2dsphere indexes. With a 2dsphere index, you can query the geospatial data for inclusion, intersection, and proximity. For more information about querying geospatial data, see Geospatial Queries.

To create a 2dsphere index, you must specify a field that contains only GeoJSON objects. For more details on this type, see the MongoDB Server manual page on GeoJSON objects.

The location.geo field in the following sample document from the theaters collection in the sample_mflix database is a GeoJSON Point object that describes the coordinates of the theater:

{
"_id" : ObjectId("59a47286cfa9a3a73e51e75c"),
"theaterId" : 104,
"location" : {
"address" : {
"street1" : "5000 W 147th St",
"city" : "Hawthorne",
"state" : "CA",
"zipcode" : "90250"
},
"geo" : {
"type" : "Point",
"coordinates" : [
-118.36559,
33.897167
]
}
}
}

The following example creates a 2dsphere index on the location.geo field:

Important

Attempting to create a geospatial index on a field that is covered by a geospatial index results in an error.

try {
String resultCreateIndex = collection.createIndex(Indexes.geo2dsphere("location.geo"));
System.out.println(String.format("Index created: %s", resultCreateIndex));
// Prints a message if a geospatial index already exists with a different configuration
} catch (MongoCommandException e) {
if (e.getErrorCodeName().equals("IndexOptionsConflict"))
System.out.println("there's an existing geospatial index with different options");
}

The following is an example of a geospatial query using the "location.geo" index.

// Stores the coordinates of the NY MongoDB headquarters
Point refPoint = new Point(new Position(-73.98456, 40.7612));
// Retrieves documents that represent locations up to 1000 meters from the specified point directly from the geospatial index
// Creates a filter to match a document
Bson filter = near("location.geo", refPoint, 1000.0, 0.0);
FindIterable<Document> cursor = collection.find(filter);

MongoDB also supports 2d indexes for calculating distances on a Euclidean plane and for working with the "legacy coordinate pairs" syntax used in MongoDB 2.2 and earlier. For more information, see the Geospatial Queries page in the MongoDB Server manual.

Unique indexes ensure that the indexed fields do not store duplicate values. By default, MongoDB creates a unique index on the _id field during the creation of a collection. To create a unique index, specify the field or combination of fields that you want to prevent duplication on and set the unique option to true.

The following example creates a unique, descending index on the theaterId field:

try {
IndexOptions indexOptions = new IndexOptions().unique(true);
String resultCreateIndex = collection.createIndex(Indexes.descending("theaterId"), indexOptions);
System.out.println(String.format("Index created: %s", resultCreateIndex));
// Prints a message if the "theaterID" field contains duplicate values
} catch (DuplicateKeyException e) {
System.out.printf("duplicate field values encountered, couldn't create index: \t%s\n", e);
}

Important

If you perform a write operation that stores a duplicate value that violates the unique index, the MongoDB Java driver raises a DuplicateKeyException, and MongoDB throws an error resembling the following:

E11000 duplicate key error index

For more information, see the Unique Indexes page in the MongoDB Server manual.

Wildcard indexes enable queries against unknown or arbitrary fields. These indexes can be beneficial if you are using a dynamic schema.

The following example creates an ascending wildcard index on all values of the location field, including values nested in subdocuments and arrays:

String resultCreateIndex = collection.createIndex(Indexes.ascending("location.$**"));
System.out.println(String.format("Index created: %s", resultCreateIndex));

For more information, see the Wildcard Indexes page in the MongoDB Server manual.

Clustered indexes instruct a collection to store documents ordered by a key value. To create a clustered index, specify the clustered index option with the _id field as the key and the unique field as true when you create your collection.

The following example creates a clustered index on the _id field in the vendors collection:

MongoDatabase database = mongoClient.getDatabase("tea");
ClusteredIndexOptions clusteredIndexOptions = new ClusteredIndexOptions(new Document("_id", 1), true);
CreateCollectionOptions createCollectionOptions = new CreateCollectionOptions().clusteredIndexOptions(clusteredIndexOptions);
database.createCollection("vendors", createCollectionOptions);

See the MongoDB Server manual sections for more information:

You can remove any unused index except the default unique index on the _id field.

The following sections show the ways to remove indexes:

  • Using an index specification document

  • Using an indexed name field

  • Using a wildcard character to remove all indexes

Pass an index specification document to the dropIndex() method to remove an index from a collection. An index specification document is a Bson instance that specifies the type of index on a specified field.

The following snippet removes an ascending index on the title field in a collection:

collection.dropIndex(Indexes.ascending("title"));

Important

If you want to drop a text index, you must use the name of the index instead. See the Remove an Index Using a Name Field section for details.

Pass the name field of the index to the dropIndex() method to remove an index from a collection.

To find the name of your index, use the listIndexes() method to see the value of the name fields in your indexes.

The following snippet retrieves and prints all the indexes in a collection:

collection.listIndexes().forEach(doc -> System.out.println(doc.toJson()));

If you call listIndex() on a collection that contains a text index, the output might resemble the following:

{ "v": 2, "key": {"_id": 1}, "name": "_id_" }
{ "v": 2, "key": {"_fts": "text", "_ftsx": 1}, "name": "title_text", "weights": {"title": 1},
"default_language": "english", "language_override": "language", "textIndexVersion": 3 }

This output tells us the names of the existing indexes are "_id" and "title_text".

The following snippet removes the "title_text" index from the collection:

collection.dropIndex("title_text");

Note

You cannot remove a single field from a compound text index. You must drop the entire index and create a new one to update the indexed fields.

Starting with MongoDB 4.2, you can drop all indexes by calling the dropIndexes() method on your collection:

collection.dropIndexes();

For prior versions of MongoDB, pass "*" as a parameter to your call to dropIndex() on your collection:

collection.dropIndex("*");

For more information about the methods in this section, see the following API Documentation:

Back

Aggregation Expression Operations