Overview
本教程向您展示如何使用 Spring Data 创建高级查询以与MongoDB交互。您学习;了解如何使用 MongoRepository 接口和 MongoTemplate 类执行筛选、更新和聚合数据等操作。
注意
本教程要求您对 Spring Data 和MongoDB有基本了解。有关将 Spring Data 与 MongoDB 结合使用的介绍,请参阅 Spring Data 框架 集成 教程。
先决条件
您必须拥有以下物品才能完成本教程:
来自 spring-data-unlocked 示例存储库的源代码。按照存储库自述文件中的说明设立和运行项目。
具有免费集群的MongoDB Atlas帐户。要学习;了解如何创建Atlas帐户和集群,请参阅MongoDB入门指南。
您首选的 IDE。
数据模型
本教程使用具有以下结构的ACID 事务数据模型:
{ "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
本教程中的应用程序是管理客户记录和事务的REST API 。
本教程向您展示如何执行以下操作:
使用
MongoRepository创建派生查询。使用
@Query注解创建查询。使用
@Update注解更新数据。查看聚合管道方法。
实现分页。
使用
MongoTemplate进行灵活操作。
使用 MongoRepository 创建派生查询。
导航到 spring-data-unlocked项目中的 src/main/java/com/mongodb/resources目录,然后打开 TransactionRepository 界面。该接口包含以下按类型查找事务的方法:
List<Transaction> findByTransactionType(String type);Spring Data 使用方法名称来创建查询。findBy 前缀指示 Spring Data 创建查询,而 TransactionType 指定要过滤的字段。
您可以通过将以下行添加到 application.properties文件来启用调试日志记录,以查看生成的查询:
logging.level.org.springframework.data.mongodb=DEBUG提示
确保 application.properties文件位于类路径中,以便 Spring Boot 可以加载指定的属性。
运行findByTransactionType查询时,控制台会显示类似于以下内容的输出:
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: transactionsTransactionRepository 接口还包括以下方法,用于按金额查找事务和按类型删除事务:
List<Transaction> findByAmountGreaterThan(double amount);void deleteByTransactionType(String type);使用 @Query 注解创建查询。
TransactionRepository 定义了一个 findByStatus() 方法,该方法使用 @Query 注解按 status字段值查找事务。此方法仅返回特定字段并对结果进行排序。
@Query( value= "{ 'status' : ?0 }", fields="{ 'createdAt': 1, 'accountDetails' : 1, 'amount' : 1}", sort = "{ createdAt: -1}")List<Transaction> findByStatus(String status);@Query 注解中的参数指定以下内容:
value指定过滤器条件。fields定义要包含在结果中的字段。sort按createdAt字段值降序对结果进行排序。
要学习;了解有关 @Query 注解的更多信息,请参阅 Spring Data MongoDB文档。
使用 @Update 注解更新数据。
TransactionRepository 接口包含一个结合使用 @Query 和 @Update 注解来更新ACID 事务状态的方法:
@Query("{ '_id' : ?0 }")@Update("{ '$set' : { 'status' : ?1 } }")void updateStatus(String id, String status);@Query 注释通过ID查找文档,@Update 注释修改状态字段。
要学习;了解更多信息,请参阅有关更新操作的 Spring Data MongoDB文档。
查看聚合管道方法。
TransactionRepository 接口包含一个使用 @Aggregation 注解来计算按ACID 事务类型分组的总金额的方法:
@Aggregation(pipeline = { "{ '$match': { 'transactionType': ?0 } }", "{ '$group': { '_id': '$transactionType', 'amount': { '$sum': '$amount' } } }", "{ '$project': { 'amount': 1 } }"})List<Transaction> getTotalAmountByTransactionType(String transactionType);此聚合管道执行以下操作:
$match按类型筛选事务。$group按类型对事务进行分组并对金额求和。$project显示总金额。
将错误事务导出到新集合。
TransactionRepository 接口还包括一个使用 $out 阶段将错误事务复制到新集合的方法:
@Aggregation(pipeline = { "{ '$match': { 'status': 'error' } }", "{ '$project': { '_id': 1, 'amount': 1, 'status': 1, 'description': 1, 'createdAt': 1} }", "{ '$out': 'error_transactions' }"})void exportErrorTransactions();调用此方法时, MongoDB会创建一个名为 error_transactions 的新集合,并插入所有处于错误状态的文档。
重要
在生产中使用此阶段之前,请查看$out操作符文档。如果目标集合已存在,则 $out 阶段会将其替换。
查看文本搜索注释。
src/main/java/com/mongodb/resources目录中的 SearchAggregate.java文件包含以下代码,用于创建执行文本搜索的自定义注解。
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;
@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.METHOD })@Aggregation(pipeline = { "{ '$search': { 'text': { 'query': ?0, 'path': ?1 } } }"})@interface SearchAggregate {}TransactionRepository 接口包含以下使用该注解的代码:
@SearchAggregateList<Transaction> search(String query, String path);实现分页。
MongoRepository 接口扩展了 PagingAndSortingRepository,后者提供分页支持。打开 TransactionService 类并添加以下方法:
public Page<Transaction> findPageableTransactions( Pageable pageable) { return transactionRepository.findAll(pageable);}src/main/java/com/mongodb/application/web目录中的 TransactionController 类包含以下接受分页参数的控制器方法:
@GetMapping("/pageable")public PagedModel<Transaction> findAll(@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "100") int sizePerPage, @RequestParam(defaultValue = "ID") String sortField, @RequestParam(defaultValue = "DESC") Sort.Direction sortDirection) { Pageable pageable = PageRequest.of(page, sizePerPage, Sort.by(sortDirection, sortField)); return new PagedModel<>(transactionService.findPageableTransactions(pageable));}在应用程序运行时,通过从终端运行以下命令来调用此终结点:
curl --location 'http://localhost:8080/transactions?page=0&sizePerPage=10&sortField=description&sortDirection=ASC'配置 MongoTemplate。
在MongoDB上执行操作时,MongoTemplate 类比 MongoRepository 类更灵活。在以下步骤中,您学习;了解如何使用 MongoTemplate 执行批量操作、查询和聚合。
导航至 src/main/java/com/mongodb/resources目录以查看名为 MongoConfig.java 的配置类,该类用于设置 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;
@Configurationpublic class MongoConfig {
@Bean public MongoClient mongoClient() { MongoClientSettings settings = MongoClientSettings.builder() .applyConnectionString(new ConnectionString("<your connection string>")) .build(); return MongoClients.create(settings); }
@Bean MongoOperations mongoTemplate(MongoClient mongoClient) { return new MongoTemplate(mongoClient, "springshop"); }}执行批量插入操作。
src/main/java/com/mongodb/domain/service目录中的 CustomerService 类包含以下一次性插入多个文档的方法:
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;}bulkOps 方法创建批量操作,将所有文档插入列表中。
使用 MongoTemplate 查询文档。
CustomerService 类包含通过电子邮件查找客户的方法:
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));}query 方法接受定义Criteria的过滤器对象。您可以使用 gt()、lt()、and() 和 or() 等方法来构建复杂查询。
要学习;了解更多信息,请参阅 Criteria 类文档。
使用 MongoTemplate 执行聚合。
src/main/java/com/mongodb/domain/model目录中的 CustomersByCity 类包含以下保存聚合结果的记录:
public record CustomersByCity( String id, int total){}CustomerService.java文件包含按城市计算客户数量的方法:
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();}此方法按城市对客户数进行分组,并计算每个城市的客户数。
测试您的查询。
通过在 IDE 中运行SpringShopApplication 类或从终端运行以下命令来运行应用应用程序:
export MONGODB_URI="<YOUR_CONNECTION_STRING>"./gradlew bootRun应用程序在端口 8080 上运行。您可以通过向前面步骤中定义的端点发送请求来测试查询。
有关在此应用程序中测试终结点的更多信息,请参阅 spring-data-unlocked 存储库中的自述文件。
其他资源
要学习有关 Spring Data MongoDB 的更多信息,请参阅Spring Data MongoDB 文档。
要学习;了解有关聚合管道的更多信息,请参阅MongoDB Server手册中的聚合。