Overview
This tutorial shows you how to create advanced queries by using Spring Data to interact with MongoDB. You learn how to use the MongoRepository interface and MongoTemplate class to perform operations such as filtering, updating, and aggregating data.
Note
This tutorial requires a basic understanding of Spring Data and MongoDB. For an introduction to using Spring Data with MongoDB, see the Spring Data Framework Integration tutorial.
Prerequisites
You must have the following items to complete this tutorial:
Source code from the spring-data-unlocked example repository. Follow the instructions in the repository's README to set up and run the project.
MongoDB Atlas account with a free cluster. To learn how to create an Atlas account and cluster, see the MongoDB Get Started guide.
Your preferred IDE.
Data Model
This tutorial uses a transaction data model that has the following structure:
{ "id": "672182814338f60133ee26e1", "transactionType": "Debit", "amount": 888.0, "currency": "USD", "status": "In Progress", "description": "Transfer to Ricardo", "createdAt": "2024-10-09T14:00:00", "accountDetails": { "originator": { "accountNumber": "2376543213", "name": "Maria", "bank": "Bank G" }, "beneficiary": { "accountNumber": "2234987651", "name": "Ricardo Mello", "bank": "Bank V" } } }
Tutorial
The application in this tutorial is a REST API that manages customer records and transactions.
This tutorial shows you how to perform the following actions:
Create derived queries by using
MongoRepository.Create queries by using the
@Queryannotation.Update data by using the
@Updateannotation.Review aggregation pipeline methods.
Implement pagination.
Use
MongoTemplatefor flexible operations.
Create derived queries by using MongoRepository.
Navigate to the src/main/java/com/mongodb/resources directory in the spring-data-unlocked project and open the TransactionRepository interface. This interface includes the following method to find transactions by type:
List<Transaction> findByTransactionType(String type);
Spring Data uses the method name to create a query. The findBy prefix instructs Spring Data to create a query, and TransactionType specifies the field to filter on.
You can enable debug logging to see the generated queries by adding the following line to your application.properties file:
logging.level.org.springframework.data.mongodb=DEBUG
Tip
Ensure that the application.properties file is in your classpath so that Spring Boot can load the specified properties.
When you run the findByTransactionType query, the console displays output similar to the following:
2024-10-15T18:30:33.855-03:00 DEBUG 28992 [SpringShop] [nio-8080-exec-6] o.s.data.mongodb.core.MongoTemplate: find using query: { "transactionType" : "Transfer"} fields: Document{{}} sort: { "transactionType" : "Transfer"} for class: class com.mongodb.Transaction in collection: transactions
The TransactionRepository interface also includes the following methods to find transactions by amount and delete transactions by type:
List<Transaction> findByAmountGreaterThan(double amount); void deleteByTransactionType(String type);
Create queries by using the @Query annotation.
The TransactionRepository defines a findByStatus() method that uses the @Query annotation to find transactions by their status field value. This method returns only specific fields and sorts the results.
List<Transaction> findByStatus(String status);
The parameters in the @Query annotation specify the following:
valuespecifies the filter criteria.fieldsdefines which fields to include in the results.sortorders the results by thecreatedAtfield value in descending order.
To learn more about the @Query annotation, see the Spring Data MongoDB documentation.
Update data by using the @Update annotation.
The TransactionRepository interface includes a method that combines the @Query and @Update annotations to update a transaction status:
void updateStatus(String id, String status);
The @Query annotation finds the document by ID, and the @Update annotation modifies the status field.
To learn more, see the Spring Data MongoDB documentation on update operations.
Review aggregation pipeline methods.
The TransactionRepository interface includes a method that uses the @Aggregation annotation to calculate the total amount grouped by transaction type:
List<Transaction> getTotalAmountByTransactionType(String transactionType);
This aggregation pipeline performs the following operations:
$matchfilters transactions by type.$groupgroups transactions by type and sums the amounts.$projectdisplays the total amount.
Export error transactions to a new collection.
The TransactionRepository interface also includes a method that uses the $out stage to copy error transactions to a new collection:
void exportErrorTransactions();
When you call this method, MongoDB creates a new collection called error_transactions and inserts all documents that have an error status.
Important
Review the $out operator documentation before you use this stage in production. The $out stage replaces the target collection if it already exists.
Review the text search annotation.
The SearchAggregate.java file in the src/main/java/com/mongodb/resources directory includes the following code that creates a custom annotation that performs a text search.
import org.springframework.data.mongodb.repository.Aggregation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; SearchAggregate { }
The TransactionRepository interface includes the following code that uses the annotation:
List<Transaction> search(String query, String path);
Implement pagination.
The MongoRepository interface extends PagingAndSortingRepository, which provides pagination support. Open your TransactionService class and add the following method:
public Page<Transaction> findPageableTransactions( Pageable pageable ) { return transactionRepository.findAll(pageable); }
The TransactionController class in the src/main/java/com/mongodb/application/web directory includes the following controller method that accepts pagination parameters:
public PagedModel<Transaction> findAll( int page, int sizePerPage, String sortField, Sort.Direction sortDirection) { Pageable pageable = PageRequest.of(page, sizePerPage, Sort.by(sortDirection, sortField)); return new PagedModel<>(transactionService.findPageableTransactions(pageable)); }
Call this endpoint by running the following command from your terminal while your application runs:
curl --location 'http://localhost:8080/transactions?page=0&sizePerPage=10&sortField=description&sortDirection=ASC'
Configure MongoTemplate.
The MongoTemplate class provides more flexibility than MongoRepository for performing operations on MongoDB. In the following steps, you learn how to use MongoTemplate to perform bulk operations, queries, and aggregations.
Navigate to the src/main/java/com/mongodb/resources directory to view the configuration class named MongoConfig.java, which sets up MongoTemplate:
package com.mongodb; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoTemplate; public class MongoConfig { public MongoClient mongoClient() { MongoClientSettings settings = MongoClientSettings.builder() .applyConnectionString(new ConnectionString("<your connection string>")) .build(); return MongoClients.create(settings); } MongoOperations mongoTemplate(MongoClient mongoClient) { return new MongoTemplate(mongoClient, "springshop"); } }
Review the Customer model.
The Customer.java file in the src/main/java/com/mongodb/model directory defines the following record:
package com.mongodb.model; public record Customer( String name, String email, String accountNumber, String phone, Address address ) { public record Address( String street, String city ) {} }
Perform bulk insert operations.
The CustomerService class in the src/main/java/com/mongodb/domain/service directory includes the following method that inserts multiple documents at once:
public int bulkCustomerSample(List<Customer> customerList) { if (findAll().isEmpty()) { BulkWriteResult result = mongoOperations.bulkOps(BulkOperations.BulkMode.ORDERED, Customer.class) .insert(customerList) .execute(); return result.getInsertedCount(); } return 0; }
The bulkOps method creates a bulk operation that inserts all documents in the list.
Query documents with MongoTemplate.
The CustomerService class includes a method that finds a customer by email:
public Customer findCustomerByEmail(String email) { return mongoOperations.query(Customer.class) .matching(query(where("email").is(email))) .one() .orElseThrow(() -> new RuntimeException("Customer not found with email: " + email)); }
The query method accepts a Criteria object that defines the filter. You can use methods such as gt(), lt(), and(), and or() to build complex queries.
To learn more, see the Criteria class documentation.
Perform aggregations with MongoTemplate.
The CustomersByCity class in the src/main/java/com/mongodb/domain/model directory contains the following record that holds aggregation results:
public record CustomersByCity( String id, int total ){}
The CustomerService.java file includes a method that counts customers by city:
public List<CustomersByCity> totalCustomerByCity() { TypedAggregation<Customer> aggregation = newAggregation(Customer.class, group("address.city") .count().as("total"), Aggregation.sort(Sort.Direction.ASC, "_id"), project(Fields.fields("total", "_id"))); AggregationResults<CustomersByCity> result = mongoOperations.aggregate(aggregation, CustomersByCity.class); return result.getMappedResults(); }
This method groups customers by city and counts the number of customers in each city.
Test your queries.
Run your application by running the SpringShopApplication class in your IDE or by running the following commands from your terminal:
export MONGODB_URI="<YOUR_CONNECTION_STRING>" ./gradlew bootRun
The application runs on port 8080. You can test your queries by sending requests to the endpoints defined in the previous steps.
For more information about testing the endpoints in this application, see the README in the spring-data-unlocked repository.
Additional Resources
To learn more about Spring Data MongoDB, see the Spring Data MongoDB documentation.
To learn more about aggregation pipelines, see Aggregation in the MongoDB Server manual.