Skip to content

Latest commit

 

History

History
902 lines (687 loc) · 31.8 KB

File metadata and controls

902 lines (687 loc) · 31.8 KB

Mapping

Rich mapping support is provided by the MappingMongoConverter. MappingMongoConverter has a rich metadata model that provides a full feature set to map domain objects to MongoDB documents. The mapping metadata model is populated by using annotations on your domain objects. However, the infrastructure is not limited to using annotations as the only source of metadata information. The MappingMongoConverter also lets you map objects to documents without providing any additional metadata, by following a set of conventions.

This section describes the features of the MappingMongoConverter, including fundamentals, how to use conventions for mapping objects to documents and how to override those conventions with annotation-based mapping metadata.

Convention-based Mapping

MappingMongoConverter has a few conventions for mapping objects to documents when no additional mapping metadata is provided. The conventions are:

  • The short Java class name is mapped to the collection name in the following manner. The class com.bigbank.SavingsAccount maps to the savingsAccount collection name.

  • All nested objects are stored as nested objects in the document and not as DBRefs.

  • The converter uses any Spring Converters registered with it to override the default mapping of object properties to document fields and values.

  • The fields of an object are used to convert to and from fields in the document. Public JavaBean properties are not used.

  • If you have a single non-zero-argument constructor whose constructor argument names match top-level field names of document, that constructor is used. Otherwise, the zero-argument constructor is used. If there is more than one non-zero-argument constructor, an exception will be thrown.

How the _id field is handled in the mapping layer.

MongoDB requires that you have an _id field for all documents. If you don’t provide one the driver will assign a ObjectId with a generated value. The "_id" field can be of any type the, other than arrays, so long as it is unique. The driver naturally supports all primitive types and Dates. When using the MappingMongoConverter there are certain rules that govern how properties from the Java class is mapped to this _id field.

The following outlines what field will be mapped to the _id document field:

  • A field annotated with @Id (org.springframework.data.annotation.Id) will be mapped to the _id field.

  • A field without an annotation but named id will be mapped to the _id field.

  • The default field name for identifiers is _id and can be customized via the @Field annotation.

Table 1. Examples for the translation of _id field definitions
Field definition Resulting Id-Fieldname in MongoDB

String id

_id

@Field String id

_id

@Field("x") String id

x

@Id String x

_id

@Field("x") @Id String x

_id

The following outlines what type conversion, if any, will be done on the property mapped to the _id document field.

  • If a field named id is declared as a String or BigInteger in the Java class it will be converted to and stored as an ObjectId if possible. ObjectId as a field type is also valid. If you specify a value for id in your application, the conversion to an ObjectId is detected to the MongoDB driver. If the specified id value cannot be converted to an ObjectId, then the value will be stored as is in the document’s _id field. This also applies if the field is annotated with @Id.

  • If a field is annotated with @MongoId in the Java class it will be converted to and stored as using its actual type. No further conversion happens unless @MongoId declares a desired field type.

  • If a field is annotated with @MongoId(FieldType.…) in the Java class it will be attempted to convert the value to the declared FieldType.

  • If a field named id id field is not declared as a String, BigInteger, or ObjectID in the Java class then you should assign it a value in your application so it can be stored 'as-is' in the document’s _id field.

  • If no field named id is present in the Java class then an implicit _id file will be generated by the driver but not mapped to a property or field of the Java class.

When querying and updating MongoTemplate will use the converter to handle conversions of the Query and Update objects that correspond to the above rules for saving documents so field names and types used in your queries will be able to match what is in your domain classes.

Data Mapping and Type Conversion

This section explains how types are mapped to and from a MongoDB representation. Spring Data MongoDB supports all types that can be represented as BSON, MongoDB’s internal document format. In addition to these types, Spring Data MongoDB provides a set of built-in converters to map additional types. You can provide your own converters to adjust type conversion. See [mapping-explicit-converters] for further details.

The following provides samples of each available type conversion:

Table 2. Type
Type Type conversion Sample

String

native

{"firstname" : "Dave"}

double, Double, float, Float

native

{"weight" : 42.5}

int, Integer, short, Short

native
32-bit integer

{"height" : 42}

long, Long

native
64-bit integer

{"height" : 42}

Date, Timestamp

native

{"date" : ISODate("2019-11-12T23:00:00.809Z")}

byte[]

native

{"bin" : { "$binary" : "AQIDBA==", "$type" : "00" }}

java.util.UUID (Legacy UUID)

native

{"uuid" : { "$binary" : "MEaf1CFQ6lSphaa3b9AtlA==", "$type" : "03" }}

Date

native

{"date" : ISODate("2019-11-12T23:00:00.809Z")}

ObjectId

native

{"_id" : ObjectId("5707a2690364aba3136ab870")}

Array, List, BasicDBList

native

{"cookies" : [ … ]}

boolean, Boolean

native

{"active" : true}

null

native

{"value" : null}

Document

native

{"value" : { … }}

Decimal128

native

{"value" : NumberDecimal(…)}

AtomicInteger
calling get() before the actual conversion

converter
32-bit integer

{"value" : "741" }

AtomicLong
calling get() before the actual conversion

converter
64-bit integer

{"value" : "741" }

BigInteger

converter
String

{"value" : "741" }

BigDecimal

converter
String

{"value" : "741.99" }

URL

converter

{"website" : "https://projects.spring.io/spring-data-mongodb/" }

Locale

converter

{"locale : "en_US" }

char, Character

converter

{"char" : "a" }

NamedMongoScript

converter
Code

{"_id" : "script name", value: (some javascript code)}

java.util.Currency

converter

{"currencyCode" : "EUR"}

Instant
(Java 8)

native

{"date" : ISODate("2019-11-12T23:00:00.809Z")}

Instant
(Joda, JSR310-BackPort)

converter

{"date" : ISODate("2019-11-12T23:00:00.809Z")}

LocalDate
(Joda, Java 8, JSR310-BackPort)

converter / native (Java8)[1]

{"date" : ISODate("2019-11-12T00:00:00.000Z")}

LocalDateTime, LocalTime
(Joda, Java 8, JSR310-BackPort)

converter / native (Java8)[2]

{"date" : ISODate("2019-11-12T23:00:00.809Z")}

DateTime (Joda)

converter

{"date" : ISODate("2019-11-12T23:00:00.809Z")}

ZoneId (Java 8, JSR310-BackPort)

converter

{"zoneId" : "ECT - Europe/Paris"}

Box

converter

{"box" : { "first" : { "x" : 1.0 , "y" : 2.0} , "second" : { "x" : 3.0 , "y" : 4.0}}

Polygon

converter

{"polygon" : { "points" : [ { "x" : 1.0 , "y" : 2.0} , { "x" : 3.0 , "y" : 4.0} , { "x" : 4.0 , "y" : 5.0}]}}

Circle

converter

{"circle" : { "center" : { "x" : 1.0 , "y" : 2.0} , "radius" : 3.0 , "metric" : "NEUTRAL"}}

Point

converter

{"point" : { "x" : 1.0 , "y" : 2.0}}

GeoJsonPoint

converter

{"point" : { "type" : "Point" , "coordinates" : [3.0 , 4.0] }}

GeoJsonMultiPoint

converter

{"geoJsonLineString" : {"type":"MultiPoint", "coordinates": [ [ 0 , 0 ], [ 0 , 1 ], [ 1 , 1 ] ] }}

Sphere

converter

{"sphere" : { "center" : { "x" : 1.0 , "y" : 2.0} , "radius" : 3.0 , "metric" : "NEUTRAL"}}

GeoJsonPolygon

converter

{"polygon" : { "type" : "Polygon", "coordinates" : [[ [ 0 , 0 ], [ 3 , 6 ], [ 6 , 1 ], [ 0 , 0 ] ]] }}

GeoJsonMultiPolygon

converter

{"geoJsonMultiPolygon" : { "type" : "MultiPolygon", "coordinates" : [ [ [ [ -73.958 , 40.8003 ] , [ -73.9498 , 40.7968 ] ] ], [ [ [ -73.973 , 40.7648 ] , [ -73.9588 , 40.8003 ] ] ] ] }}

GeoJsonLineString

converter

{ "geoJsonLineString" : { "type" : "LineString", "coordinates" : [ [ 40 , 5 ], [ 41 , 6 ] ] }}

GeoJsonMultiLineString

converter

{"geoJsonLineString" : { "type" : "MultiLineString", coordinates: [ [ [ -73.97162 , 40.78205 ], [ -73.96374 , 40.77715 ] ], [ [ -73.97880 , 40.77247 ], [ -73.97036 , 40.76811 ] ] ] }}

Mapping Configuration

Unless explicitly configured, an instance of MappingMongoConverter is created by default when you create a MongoTemplate. You can create your own instance of the MappingMongoConverter. Doing so lets you dictate where in the classpath your domain classes can be found, so that Spring Data MongoDB can extract metadata and construct indexes. Also, by creating your own instance, you can register Spring converters to map specific classes to and from the database.

You can configure the MappingMongoConverter as well as com.mongodb.client.MongoClient and MongoTemplate by using either Java-based or XML-based metadata. The following example uses Spring’s Java-based configuration:

Example 1. @Configuration class to configure MongoDB mapping support
@Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {

  @Override
  public String getDatabaseName() {
    return "database";
  }

  // the following are optional

  @Override
  public String getMappingBasePackage() { (1)
    return "com.bigbank.domain";
  }

  @Override
  void configureConverters(MongoConverterConfigurationAdapter adapter) { (2)

  	adapter.registerConverter(new org.springframework.data.mongodb.test.PersonReadConverter());
  	adapter.registerConverter(new org.springframework.data.mongodb.test.PersonWriteConverter());
  }

  @Bean
  public LoggingEventListener<MongoMappingEvent> mappingEventsListener() {
    return new LoggingEventListener<MongoMappingEvent>();
  }
}
  1. The mapping base package defines the root path used to scan for entities used to pre initialize the MappingContext. By default the configuration classes package is used.

  2. Configure additional custom converters for specific domain types that replace the default mapping procedure for those types with your custom implementation.

AbstractMongoClientConfiguration requires you to implement methods that define a com.mongodb.client.MongoClient as well as provide a database name. AbstractMongoClientConfiguration also has a method named getMappingBasePackage(…) that you can override to tell the converter where to scan for classes annotated with the @Document annotation.

You can add additional converters to the converter by overriding the customConversionsConfiguration method. MongoDB’s native JSR-310 support can be enabled through MongoConverterConfigurationAdapter.useNativeDriverJavaTimeCodecs(). Also shown in the preceding example is a LoggingEventListener, which logs MongoMappingEvent instances that are posted onto Spring’s ApplicationContextEvent infrastructure.

Note
AbstractMongoClientConfiguration creates a MongoTemplate instance and registers it with the container under the name mongoTemplate.

Spring’s MongoDB namespace lets you enable mapping functionality in XML, as the following example shows:

Example 2. XML schema to configure MongoDB mapping support
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:mongo="http://www.springframework.org/schema/data/mongo"
  xsi:schemaLocation="
    http://www.springframework.org/schema/data/mongo https://www.springframework.org/schema/data/mongo/spring-mongo.xsd
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <!-- Default bean name is 'mongo' -->
  <mongo:mongo-client host="localhost" port="27017"/>

  <mongo:db-factory dbname="database" mongo-ref="mongoClient"/>

  <!-- by default look for a Mongo object named 'mongo' - default name used for the converter is 'mappingConverter' -->
  <mongo:mapping-converter base-package="com.bigbank.domain">
    <mongo:custom-converters>
      <mongo:converter ref="readConverter"/>
      <mongo:converter>
        <bean class="org.springframework.data.mongodb.test.PersonWriteConverter"/>
      </mongo:converter>
    </mongo:custom-converters>
  </mongo:mapping-converter>

  <bean id="readConverter" class="org.springframework.data.mongodb.test.PersonReadConverter"/>

  <!-- set the mapping converter to be used by the MongoTemplate -->
  <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    <constructor-arg name="mongoConverter" ref="mappingConverter"/>
  </bean>

  <bean class="org.springframework.data.mongodb.core.mapping.event.LoggingEventListener"/>

</beans>

The base-package property tells it where to scan for classes annotated with the @org.springframework.data.mongodb.core.mapping.Document annotation.

Metadata-based Mapping

To take full advantage of the object mapping functionality inside the Spring Data MongoDB support, you should annotate your mapped objects with the @Document annotation. Although it is not necessary for the mapping framework to have this annotation (your POJOs are mapped correctly, even without any annotations), it lets the classpath scanner find and pre-process your domain objects to extract the necessary metadata. If you do not use this annotation, your application takes a slight performance hit the first time you store a domain object, because the mapping framework needs to build up its internal metadata model so that it knows about the properties of your domain object and how to persist them. The following example shows a domain object:

Example 3. Example domain object
package com.mycompany.domain;

@Document
public class Person {

  @Id
  private ObjectId id;

  @Indexed
  private Integer ssn;

  private String firstName;

  @Indexed
  private String lastName;
}
Important
The @Id annotation tells the mapper which property you want to use for the MongoDB _id property, and the @Indexed annotation tells the mapping framework to call createIndex(…) on that property of your document, making searches faster. Automatic index creation is only done for types annotated with @Document.
Warning
Auto index creation is disabled by default and needs to be enabled through the configuration (see Index Creation).

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.

Warning
=== Map like structures, unless annotated with @WildcardIndexed, are skipped by the IndexResolver because the map key, which cannot be resolved from static metadata, needs to be part of the index definition. ===
Example 4. Programmatic Index Creation for a single Domain Type
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);
  }
}
Example 5. Programmatic Index Creation for all Initial Entities
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.

Note

To turn automatic index creation ON please override autoIndexCreation() in your configuration.

@Configuration
public class Config extends AbstractMongoClientConfiguration {

  @Override
  public boolean autoIndexCreation() {
    return true;
  }

// ...
}
Important
Automatic index creation is turned OFF by default as of version 3.0.

Mapping Annotation Overview

The MappingMongoConverter can use metadata to drive the mapping of objects to documents. The following annotations are available:

  • @Id: Applied at the field level to mark the field used for identity purpose.

  • @MongoId: Applied at the field level to mark the field used for identity purpose. Accepts an optional FieldType to customize id conversion.

  • @Document: Applied at the class level to indicate this class is a candidate for mapping to the database. You can specify the name of the collection where the data will be stored.

  • @DBRef: Applied at the field to indicate it is to be stored using a com.mongodb.DBRef.

  • @DocumentReference: Applied at the field to indicate it is to be stored as a pointer to another document. This can be a single value (the id by default), or a Document provided via a converter.

  • @Indexed: Applied at the field level to describe how to index the field.

  • @CompoundIndex (repeatable): Applied at the type level to declare Compound Indexes.

  • @GeoSpatialIndexed: Applied at the field level to describe how to geoindex the field.

  • @TextIndexed: Applied at the field level to mark the field to be included in the text index.

  • @HashIndexed: Applied at the field level for usage within a hashed index to partition data across a sharded cluster.

  • @Language: Applied at the field level to set the language override property for text index.

  • @Transient: By default, all fields are mapped to the document. This annotation excludes the field where it is applied from being stored in the database. Transient properties cannot be used within a persistence constructor as the converter cannot materialize a value for the constructor argument.

  • @PersistenceConstructor: Marks a given constructor - even a package protected one - to use when instantiating the object from the database. Constructor arguments are mapped by name to the key values in the retrieved Document.

  • @Value: This annotation is part of the Spring Framework . Within the mapping framework it can be applied to constructor arguments. This lets you use a Spring Expression Language statement to transform a key’s value retrieved in the database before it is used to construct a domain object. In order to reference a property of a given document one has to use expressions like: @Value("#root.myProperty") where root refers to the root of the given document.

  • @Field: Applied at the field level it allows to describe the name and type of the field as it will be represented in the MongoDB BSON document thus allowing the name and type to be different than the fieldname of the class as well as the property type.

  • @Version: Applied at field level is used for optimistic locking and checked for modification on save operations. The initial value is zero (one for primitive types) which is bumped automatically on every update.

The mapping metadata infrastructure is defined in a separate spring-data-commons project that is technology agnostic. Specific subclasses are using in the MongoDB support to support annotation based metadata. Other strategies are also possible to put in place if there is demand.

Here is an example of a more complex mapping.

@Document
@CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}")
public class Person<T extends Address> {

  @Id
  private String id;

  @Indexed(unique = true)
  private Integer ssn;

  @Field("fName")
  private String firstName;

  @Indexed
  private String lastName;

  private Integer age;

  @Transient
  private Integer accountTotal;

  @DBRef
  private List<Account> accounts;

  private T address;

  public Person(Integer ssn) {
    this.ssn = ssn;
  }

  @PersistenceConstructor
  public Person(Integer ssn, String firstName, String lastName, Integer age, T address) {
    this.ssn = ssn;
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.address = address;
  }

  public String getId() {
    return id;
  }

  // no setter for Id.  (getter is only exposed for some unit testing)

  public Integer getSsn() {
    return ssn;
  }

// other getters/setters omitted
}
Tip

@Field(targetType=…​) can come in handy when the native MongoDB type inferred by the mapping infrastructure does not match the expected one. Like for BigDecimal, which is represented as String instead of Decimal128, just because earlier versions of MongoDB Server did not have support for it.

public class Balance {

  @Field(targetType = DECIMAL128)
  private BigDecimal value;

  // ...
}

You may even consider your own, custom annotation.

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Field(targetType = FieldType.DECIMAL128)
public @interface Decimal128 { }

// ...

public class Balance {

  @Decimal128
  private BigDecimal value;

  // ...
}

Customized Object Construction

The mapping subsystem allows the customization of the object construction by annotating a constructor with the @PersistenceConstructor annotation. The values to be used for the constructor parameters are resolved in the following way:

  • If a parameter is annotated with the @Value annotation, the given expression is evaluated and the result is used as the parameter value.

  • If the Java type has a property whose name matches the given field of the input document, then it’s property information is used to select the appropriate constructor parameter to pass the input field value to. This works only if the parameter name information is present in the java .class files which can be achieved by compiling the source with debug information or using the new -parameters command-line switch for javac in Java 8.

  • Otherwise a MappingException will be thrown indicating that the given constructor parameter could not be bound.

class OrderItem {

  private @Id String id;
  private int quantity;
  private double unitPrice;

  OrderItem(String id, @Value("#root.qty ?: 0") int quantity, double unitPrice) {
    this.id = id;
    this.quantity = quantity;
    this.unitPrice = unitPrice;
  }

  // getters/setters ommitted
}

Document input = new Document("id", "4711");
input.put("unitPrice", 2.5);
input.put("qty",5);
OrderItem item = converter.read(OrderItem.class, input);
Note
The SpEL expression in the @Value annotation of the quantity parameter falls back to the value 0 if the given property path cannot be resolved.

Additional examples for using the @PersistenceConstructor annotation can be found in the MappingMongoConverterUnitTests test suite.

Compound Indexes

Compound indexes are also supported. They are defined at the class level, rather than on individual properties.

Note
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:

Example 6. Example Compound Index Usage
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;

}
Tip

@CompoundIndex is repeatable using @CompoundIndexes as its container.

@Document
@CompoundIndex(name = "cmp-idx-one", def = "{'firstname': 1, 'lastname': -1}")
@CompoundIndex(name = "cmp-idx-two", def = "{'address.city': -1, 'address.street': 1}")
public class Person {

  String firstname;
  String lastname;

  Address address;

  // ...
}

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:

Example 7. Example Hashed Index Usage
@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:

Example 8. Example Hashed Index Usage togehter with simple index
@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:

Example 9. Example Composed Hashed Index Usage
@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.

Note

Although index creation via annotations comes in handy for many scenarios cosider taking over more control by setting up indices manually via IndexOperations.

mongoOperations.indexOpsFor(Jedi.class)
  .ensureIndex(HashedIndex.hashed("useTheForce"));

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.

Example 10. Programmatic WildcardIndex setup
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.

Example 11. Wildcard index on domain type
@Document
@WildcardIndexed
public class Product {
	// …
}
db.product.createIndex({ "$**" : 1 },{})

The wildcardProjection can be used to specify keys to in-/exclude in the index.

Example 12. Wildcard index with 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.

Example 13. Wildcard index on property
@Document
public class User {
    private @Id String id;

    @WildcardIndexed
    private UserMetadata userMetadata;
}
db.user.createIndex({ "userMetadata.$**" : 1 }, {})

Text Indexes

Note
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:

Example 14. Example Text Index Usage
@Document(language = "spanish")
class SomeEntity {

    @TextIndexed String foo;

    @Language String lang;

    Nested nested;
}

class Nested {

    @TextIndexed(weight=5) String bar;
    String roo;
}

Mapping Framework Events

Events are fired throughout the lifecycle of the mapping process. This is described in the Lifecycle Events section.

Declaring these beans in your Spring ApplicationContext causes them to be invoked whenever the event is dispatched.


1. Uses UTC zone offset. Configure via MongoConverterConfigurationAdapter
2. Uses UTC zone offset. Configure via MongoConverterConfigurationAdapter