Docs 菜单
Docs 主页
/ /

教程:使用 Spring Data 查询MongoDB

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

注意

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

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

  • 来自 spring-data-unlocked 示例存储库的源代码。按照存储库自述文件中的说明设立和运行项目。

  • 具有免费集群的MongoDB Atlas帐户。要学习;了解如何创建Atlas帐户和集群,请参阅MongoDB入门指南。

  • Java 21 或更高版本。

  • Gradle 8.8 或更高版本。

  • 您首选的 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"
}
}
}

本教程中的应用程序是管理客户记录和事务的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 定义要包含在结果中的字段。

  • sortcreatedAt字段值降序对结果进行排序。

要学习;了解有关@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 接口包含以下使用该注解的代码:

@SearchAggregate
List<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;
@Configuration
public 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手册中的聚合。

后退

Spring Data MongoDB