对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。

教程:使用 Spring Data 查询MongoDB

本教程向您展示如何使用 Spring Data 创建高级查询以与MongoDB交互。您学习;了解如何使用 MongoRepository 接口和 MongoTemplate 类执行筛选、更新和聚合数据等操作。

注意

本教程要求您对 Spring Data 和MongoDB有基本了解。有关将 Spring Data 与 MongoDB 结合使用的介绍,请参阅 Spring Data 框架 集成 教程。

您必须拥有以下物品才能完成本教程:

本教程使用具有以下结构的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" } }}

本教程中的应用程序是管理客户记录和事务的REST API 。

本教程向您展示如何执行以下操作:

  • 使用 MongoRepository 创建派生查询。

  • 使用 @Query 注解创建查询。

  • 使用 @Update 注解更新数据。

  • 查看聚合管道方法。

  • 实现分页。

  • 使用 MongoTemplate 进行灵活操作。

1

导航到 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: transactions

TransactionRepository 接口还包括以下方法,用于按金额查找事务和按类型删除事务:

List<Transaction> findByAmountGreaterThan(double amount);void deleteByTransactionType(String type);
2

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文档。

3

TransactionRepository 接口包含一个结合使用 @Query 和 @Update 注解来更新ACID 事务状态的方法:

@Query("{ '_id' : ?0 }")@Update("{ '$set' : { 'status' : ?1 } }")void updateStatus(String id, String status);

@Query 注释通过ID查找文档,@Update 注释修改状态字段。

要学习;了解更多信息,请参阅有关更新操作的 Spring Data MongoDB文档。

4

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 显示总金额。

5

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 阶段会将其替换。

6

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);
7

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'
8

在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"); }}
9

src/main/java/com/mongodb/model目录中的 Customer.java文件定义以下记录:

package com.mongodb.model; public record Customer( String name, String email, String accountNumber, String phone, Address address) { public record Address( String street, String city ) {}}
10

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 方法创建批量操作,将所有文档插入列表中。

11

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 类文档。

12

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();}

此方法按城市对客户数进行分组,并计算每个城市的客户数。

13

通过在 IDE 中运行SpringShopApplication 类或从终端运行以下命令来运行应用应用程序:

export MONGODB_URI="<YOUR_CONNECTION_STRING>"./gradlew bootRun

应用程序在端口 8080 上运行。您可以通过向前面步骤中定义的端点发送请求来测试查询。

有关在此应用程序中测试终结点的更多信息,请参阅 spring-data-unlocked 存储库中的自述文件。

要学习有关 Spring Data MongoDB 的更多信息,请参阅Spring Data MongoDB 文档。

要学习;了解有关聚合管道的更多信息,请参阅MongoDB Server手册中的聚合。