Using MongoDB with Spring Data MongoDB
We will discuss about non-reactive programming with Spring Data MongoDB
Project Setup
Setup the Spring boot project:
- Add the maven dependency org.springframework.boot:spring-boot-starter-data-mongodb
- Specify the spring.data.mongodb.uri
Manipulating MongodDB data
Spring Data MongoDB offers different abstraction levels, allowing you to store/retrieve data in several ways, depending on the level of abstraction.
Using Mapped Entities
You can annotating your persistence entities with annotations and then, just performing CRUD operations over them.
This mechanism uses the Java-MongoDB mapping mechanism, applying appropriate conversions for every value to send/retrieve.
Using a MongoOperations implementation like MongoTemplate
Interface org.springframework.data.mongodb.core.MongoOperation and its implementation org.springframework.data.mongodb.core.MongoTemplate, expose methods for retrieving/updating data into MongoDB.
Some of the methods retrieve the entity class to map the data with/to, in which case, the library apply the appropriate conversions.
Some other methods work in a lower abstraction level, executing commands over the MongoDB API, so no conversiosn are applied since the receive a json string, or one or several instances of org.bson.Document class.
Executing Aggregation Pipeline with MongoOperations
Interface org.springframework.data.mongodb.core.MongoOperation and its implementation org.springframework.data.mongodb.core.MongoTemplate, expose aggregate method that runs an aggregation pipeline over MongoDB and returns an org.springframework.data.mongodb.core.aggregation.AggregationResults object.
Note that AggregationResults object is an iterable that returns both the mapped results and and raw results (unmapped document) on every iteration.
It is important to remark that on building the org.springframework.data.mongodb.core.aggregation.Aggregation, the usage of the option allowDiskUsse with true value is recommended so MongoDb servers are not limited by the memory.
Useful Aggregation Operations
- MatchOperation
- ProjectionOperation
- SortOperation
- FacetOperation
- UnwindOperation
Custom Aggregation Operations and Expressions
You can build any extras org.springframework.data.mongodb.core.aggregation.AggregationOperation, by implementing such interface, and overriding the following methods:
- getOperator should return the MongoDB operator of such operation.
- toDocument should return the instance of org.bson.Document that represents the object with paramenters of such operator.
Please, note that there are 2 interfaces for operations exposing and consuming fields: org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation and org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation.
In case of requiring new expressions, that can be done by creating new implementations of org.springframework.data.mongodb.core.aggregation.AggregationExpression interface, implementing the toDocument method that returns the org.bson.Document instance for current expression, given an org.springframework.data.mongodb.core.aggregation.AggregationOperationContext.
Logging
I would recommend on non productive environments to set the logger of org.springframework.data.mongodb.core.MongoTemplate to debug.
Add Spring Custom converters
Setting Up Spring Custom Converters
In order to add converters, we just need to create a org.springframework.data.mongodb.core.convert.MongoCustomConversions bean with the list of converters to use.
Remember to implement safety checks in the converters so they return null when value to convert is null.
I also suggest to register the converters as @org.springframework.stereotype.Compontent, and use the @org.springframeworkg.data.convert.ReadingConverter and @org.springframeworkg.data.convert.WritingConverter annotations.
Java 8 Date API converters
Since the Spring Data MongoDB works with java.util.Date, I recommend to add custom Spring converters for converting from/to Java 8 API dates, using a unique ZoneOffset like ZoneOffset.UTC.
Retrieving JSON value
When retrieved value is an Object, you can map it to String property so JSON value is conveniently stored. When retrieved value is an Array, you need a converter that converts any List<?> to a String, and retrieve there the JSON string representation of such List.
You can create a converter that converts any List<?> to