Index Creation
Spring Data MongoDB can automatically create indexes for entity types annotated with @Document
.
Index creation must be explicitly enabled since version 3.0 to prevent undesired effects with collection lifecyle and performance impact.
Indexes are automatically created for the initial entity set on application startup and when accessing an entity type for the first time while the application runs.
We generally recommend explicit index creation for application-based control of indexes as Spring Data cannot automatically create indexes for collections that were recreated while the application was running.
IndexResolver
provides an abstraction for programmatic index definition creation if you want to make use of @Indexed
annotations such as @GeoSpatialIndexed
, @TextIndexed
, @CompoundIndex
and @WildcardIndexed
.
You can use index definitions with IndexOperations
to create indexes.
A good point in time for index creation is on application startup, specifically after the application context was refreshed, triggered by observing ContextRefreshedEvent
.
This event guarantees that the context is fully initialized.
Note that at this time other components, especially bean factories might have access to the MongoDB database.
|
class MyListener {
@EventListener(ContextRefreshedEvent.class)
public void initIndicesAfterStartup() {
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext = mongoTemplate
.getConverter().getMappingContext();
IndexResolver resolver = new MongoPersistentEntityIndexResolver(mappingContext);
IndexOperations indexOps = mongoTemplate.indexOps(DomainType.class);
resolver.resolveIndexFor(DomainType.class).forEach(indexOps::ensureIndex);
}
}
class MyListener{
@EventListener(ContextRefreshedEvent.class)
public void initIndicesAfterStartup() {
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext = mongoTemplate
.getConverter().getMappingContext();
// consider only entities that are annotated with @Document
mappingContext.getPersistentEntities()
.stream()
.filter(it -> it.isAnnotationPresent(Document.class))
.forEach(it -> {
IndexOperations indexOps = mongoTemplate.indexOps(it.getType());
resolver.resolveIndexFor(it.getType()).forEach(indexOps::ensureIndex);
});
}
}
Alternatively, if you want to ensure index and collection presence before any component is able to access your database from your application, declare a @Bean
method for MongoTemplate
and include the code from above before returning the MongoTemplate
object.
To turn automatic index creation ON please override
|
Automatic index creation is turned OFF by default as of version 3.0. |
Compound Indexes
Compound indexes are also supported. They are defined at the class level, rather than on individual properties.
Compound indexes are very important to improve the performance of queries that involve criteria on multiple fields |
Here’s an example that creates a compound index of lastName
in ascending order and age
in descending order:
package com.mycompany.domain;
@Document
@CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}")
public class Person {
@Id
private ObjectId id;
private Integer age;
private String firstName;
private String lastName;
}
|
Hashed Indexes
Hashed indexes allow hash based sharding within a sharded cluster. Using hashed field values to shard collections results in a more random distribution. For details, refer to the MongoDB Documentation.
Here’s an example that creates a hashed index for _id
:
@Document
public class DomainType {
@HashIndexed @Id String id;
// ...
}
Hashed indexes can be created next to other index definitions like shown below, in that case both indices are created:
@Document
public class DomainType {
@Indexed
@HashIndexed
String value;
// ...
}
In case the example above is too verbose, a compound annotation allows to reduce the number of annotations that need to be declared on a property:
@Document
public class DomainType {
@IndexAndHash(name = "idx...") (1)
String value;
// ...
}
@Indexed
@HashIndexed
@Retention(RetentionPolicy.RUNTIME)
public @interface IndexAndHash {
@AliasFor(annotation = Indexed.class, attribute = "name") (1)
String name() default "";
}
1 | Potentially register an alias for certain attributes of the meta annotation. |
Although index creation via annotations comes in handy for many scenarios cosider taking over more control by setting up indices manually via
|
Wildcard Indexes
A WildcardIndex
is an index that can be used to include all fields or specific ones based a given (wildcard) pattern.
For details, refer to the MongoDB Documentation.
The index can be set up programmatically using WildcardIndex
via IndexOperations
.
mongoOperations
.indexOps(User.class)
.ensureIndex(new WildcardIndex("userMetadata"));
db.user.createIndex({ "userMetadata.$**" : 1 }, {})
The @WildcardIndex
annotation allows a declarative index setup that can used either with a document type or property.
If placed on a type that is a root level domain entity (one annotated with @Document
) , the index resolver will create a
wildcard index for it.
@Document
@WildcardIndexed
public class Product {
// …
}
db.product.createIndex({ "$**" : 1 },{})
The wildcardProjection
can be used to specify keys to in-/exclude in the index.
wildcardProjection
@Document
@WildcardIndexed(wildcardProjection = "{ 'userMetadata.age' : 0 }")
public class User {
private @Id String id;
private UserMetadata userMetadata;
}
db.user.createIndex(
{ "$**" : 1 },
{ "wildcardProjection" :
{ "userMetadata.age" : 0 }
}
)
Wildcard indexes can also be expressed by adding the annotation directly to the field.
Please note that wildcardProjection
is not allowed on nested paths such as properties.
Projections on types annotated with @WildcardIndexed
are omitted during index creation.
@Document
public class User {
private @Id String id;
@WildcardIndexed
private UserMetadata userMetadata;
}
db.user.createIndex({ "userMetadata.$**" : 1 }, {})
Text Indexes
The text index feature is disabled by default for MongoDB v.2.4. |
Creating a text index allows accumulating several fields into a searchable full-text index.
It is only possible to have one text index per collection, so all fields marked with @TextIndexed
are combined into this index.
Properties can be weighted to influence the document score for ranking results.
The default language for the text index is English.To change the default language, set the language
attribute to whichever language you want (for example,@Document(language="spanish")
).
Using a property called language
or @Language
lets you define a language override on a per-document base.
The following example shows how to created a text index and set the language to Spanish:
@Document(language = "spanish")
class SomeEntity {
@TextIndexed String foo;
@Language String lang;
Nested nested;
}
class Nested {
@TextIndexed(weight=5) String bar;
String roo;
}