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.