Spring Data MongoDB

repository·main·Indexed 23 days ago

https://github.com/spring-projects/spring-data-mongodb

An integration layer between Spring applications and MongoDB that enables a POJO-centric programming model and repository-style data access. It provides core API usage via template classes like MongoTemplate and a lightweight repository abstraction. Features include type-safe queries and updates for Kotlin, MongoDB index specifications via the Index class, and support for MongoDB Java Driver 4.x+.

Tokens
61.7K
Snippets
153
Records
237
Agent score
82%

What's inside Spring Data MongoDB

  1. Overview of Spring Data MongoDB features

    main

    Spring Data MongoDB provides a high-level abstraction for interacting with MongoDB, offering several key capabilities:

    • Configuration Support: Use Java-based @Configuration classes or XML namespaces to configure Mongo driver instances and replica sets.
    • MongoTemplate: A helper class for common MongoDB operations, including ad-hoc CRUD, incrementing counters, and accessing low-level driver artifacts like com.mongodb.client.MongoDatabase via callback methods.
    • Object Mapping: Integrated mapping between MongoDB documents and POJOs using Spring's Conversion Service and extensible annotation-based metadata.
    • Exception Translation: Automatically translates MongoDB-specific exceptions into Spring's portable Data Access Exception hierarchy.
    • Querying & DSLs: Provides Java-based Query, Criteria, and Update DSLs, as well as GeoSpatial integration.
    • Repository Support: Automatic implementation of Repository interfaces, including support for custom query methods and QueryDSL integration for type-safe queries.
    • Advanced Features: Supports Multi-Document Transactions, Vector Search (with declarative Repository support), Vector Indexes, and Ahead Of Time (AOT) optimizations.
    • Lifecycle Events: Provides hooks for persistence and mapping lifecycle events.
  2. Overview of Spring Data MongoDB

    main

    Spring Data MongoDB provides integration between the Spring Framework and MongoDB. It offers two primary ways to interact with the database:

    1. Template Classes: Core API usage via template classes (e.g., MongoTemplate) for fine-grained control over database operations.
    2. Repositories: A lightweight, repository-style data access abstraction that allows for a consistent programming model across different Spring Data modules.

    Key areas of focus include MongoDB connectivity, repository usage, observability integration, and specialized support for Kotlin.

  3. Use MongoTemplate and ReactiveMongoTemplate for MongoDB interaction

    main

    MongoTemplate (imperative) and ReactiveMongoTemplate (reactive) are the central classes in Spring Data MongoDB for interacting with the database. They provide convenience operations for CRUD (Create, Read, Update, Delete) and handle the mapping between your domain objects and MongoDB documents.

    Key Characteristics:

    • Thread-safety: Once configured, MongoTemplate is thread-safe and can be reused across multiple instances.
    • Interface Preference: It is recommended to reference operations via the MongoOperations interface rather than the concrete MongoTemplate class.
    • Domain Object Support: Unlike the base MongoDB driver which works with Document objects, these templates allow you to pass and receive your own domain objects directly.
  4. How Reactive MongoDB Repositories work

    main

    Spring Data MongoDB is built on the MongoDB Reactive Streams driver, providing interoperability with the Reactive Streams initiative.

    While the API is dynamic (defined by your query methods), you can choose your preferred composition library by extending specific interfaces:

    • Project Reactor: Use ReactiveCrudRepository or ReactiveSortingRepository. These return Flux and Mono types.
    • RxJava3: Use RxJava3CrudRepository or RxJava3SortingRepository.

    Spring Data handles the conversion between these reactive wrapper types behind the scenes.

  5. How Score and Similarity work in Vector Search

    main

    In the context of Spring Data MongoDB vector searches, Score and Similarity are used to handle the similarity values returned by MongoDB.

    • Score: Used to specify a threshold. For example, Score.of(0.9) returns results with a similarity of 0.9 or greater.
    • Similarity: Similar to Score, Similarity.of(0.9) also returns results with a similarity of 0.9 or greater.
    • Range<Similarity>: Allows for a bounded similarity search. For example, Similarity.between(0.5, 1) returns results with a similarity between 0.5 and 1.0 or greater.

    Note that the scoring function is not configurable via these objects because it is tied to the MongoDB index configuration.

  6. Configure AuditorAware for Auditing

    main

    Auditing requires a mechanism to determine the current user (the 'auditor'). You do this by providing a bean that implements AuditorAware<T> (for imperative) or ReactiveAuditorAware<T> (for reactive).

    If you have only one such bean in your ApplicationContext, Spring Data MongoDB will pick it up automatically. If you have multiple implementations, you must specify which one to use by setting the auditorAwareRef attribute in your enablement annotation.

    // Imperative example
    @Bean
    public AuditorAware<AuditableUser> myAuditorProvider() {
        return new AuditorAwareImpl();
    }
    
    // Reactive example
    @Bean
    public ReactiveAuditorAware<AuditableUser> myAuditorProvider() {
        return new ReactiveAuditorAwareImpl();
    }
  7. What are Property Converters and when to use them

    main

    While type-based conversion (via CustomConversions) applies to all instances of a specific type, Property Converters allow you to define conversion rules on a per-property basis.

    Use Property Converters when you only want to transform specific values or properties of a type rather than the entire type globally. A PropertyValueConverter can transform a value into its store representation (write) and back (read). It has access to a ValueConversionContext which provides mapping metadata and direct read/write methods.

  8. How the `_id` field is handled in the mapping layer

    main

    MongoDB requires an _id field. Spring Data MongoDB maps Java properties to this field using the following rules:

    1. A property annotated with @Id maps to _id.
    2. A property named id (without annotation) maps to _id.

    Type Conversion for _id

    • String: Converted to ObjectId if possible via Converter<String, ObjectId>. If conversion fails, it is stored as a string.
    • Date: Converted to and stored as ObjectId.
    • BigInteger: Converted to and stored as ObjectId.

    Using @MongoId for fine-grained control

    If you need to bypass default conversion logic (e.g., when dealing with legacy data), use @MongoId:

    • @MongoId String id: Treated as a String without conversion.
    • @MongoId ObjectId id: Treated as an ObjectId.
    • @MongoId(FieldType.OBJECT_ID) String id: Treated as ObjectId if the string is a valid hex, otherwise as String (default behavior).
    public class PlainStringId {
      @MongoId String id;
    }
    
    public class PlainObjectId {
      @MongoId ObjectId id;
    }
    
    public class StringToObjectId {
      @MongoId(FieldType.OBJECT_ID) String id;
    }
  9. Use GeoJSON Jackson Modules for de/serialization

    main

    When using Spring Data's core web infrastructure, the MongoDB module automatically registers Jackson Modules to the ObjectMapper to handle de/serialization of common Spring Data domain types. Specifically, the MongoDB module provides GeoJsonDeserializers for the following GeoJSON types via GeoJsonConfiguration and the GeoJsonModule:

    • org.springframework.data.mongodb.core.geo.GeoJsonPoint
    • org.springframework.data.mongodb.core.geo.GeoJsonMultiPoint
    • org.springframework.data.mongodb.core.geo.GeoJsonLineString
    • org.springframework.data.mongodb.core.geo.GeoJsonMultiLineString
    • org.springframework.data.mongodb.core.geo.GeoJsonPolygon
    • org.springframework.data.mongodb.core.geo.GeoJsonMultiPolygon
  10. Implement a custom WriteConcernResolver

    main

    For advanced scenarios, you can implement the WriteConcernResolver interface to apply different WriteConcern values on a per-operation basis (e.g., based on the POJO type).

    The resolve(MongoAction action) method provides a MongoAction object containing context such as the collection name, the POJO class, the operation type (REMOVE, UPDATE, INSERT, INSERT_LIST, or SAVE), and the converted Document.

    public class MyAppWriteConcernResolver implements WriteConcernResolver {
    
    @Override
      public WriteConcern resolve(MongoAction action) {
        if (action.getEntityType().getSimpleName().contains("Audit")) {
          return WriteConcern.ACKNOWLEDGED;
        } else if (action.getEntityType().getSimpleName().contains("Metadata")) {
          return WriteConcern.JOURNALED;
        }
        return action.getDefaultWriteConcern();
      }
    }
  11. Use Explicit Client-Side Field Level Encryption (CSFLE)

    main

    Explicit encryption uses the @ExplicitEncrypted annotation to perform encryption and decryption tasks via the MongoDB driver's encryption library. This annotation combines @Encrypted (for JSON Schema) and a PropertyConverter.

    Encryption Behavior by Type

    • Simple types (e.g., String): Encrypts the value if not null.
    • Objects (e.g., Address): Encrypts the entire object and all nested fields as a single Document. To encrypt specific sub-fields, annotate those sub-fields individually.
    • Collections/Maps: Encrypted as a single value, not per entry.

    Referencing Data Encryption Keys (DEK)

    You can reference a DEK via its id or an alternative name using @EncryptedField:

    • altKeyName = "secret-key": Uses the DEK with that alternative name.
    • altKeyName = "/name": Uses a field reference to read a value from the document to use as the key lookup.
  12. Implement Optimistic Locking with @Version

    main

    The @Version annotation ensures that updates are only applied if the document's version in the database matches the version in your domain object. If another process has modified the document in the meantime, an OptimisticLockingFailureException is thrown.

    Key Behaviors

    • Initialization: When inserting, the version is automatically initialized (e.g., 0 for Integer, 1 for int).
    • Automatic Increment: MongoTemplate automatically increments the version property during updates if it is included in the update.
    • Removal: As of version 2.2, MongoOperations also checks the version when removing an entity.

    Best Practices

    • Write Concern: Optimistic locking requires write acknowledgement. Using WriteConcern.UNACKNOWLEDGED may cause exceptions to be silently swallowed.
    • Bypassing Locking: To delete an object regardless of its version, use CrudRepository.deleteById(ID) instead of delete(Object).
    @Document
    class Person {
      @Id String id;
      String firstname;
      String lastname;
      @Version Long version;
    }
    
    // Usage
    Person daenerys = template.insert(new Person("Daenerys"));
    Person tmp = template.findOne(query(where("id").is(daenerys.getId())), Person.class);
    
    daenerys.setLastname("Targaryen");
    template.save(daenerys); // version becomes 1
    
    template.save(tmp); // throws OptimisticLockingFailureException because tmp.version is still 0