Spring Data MongoDB 是 Spring 生态中对 MongoDB 的官方支持,提供了 Repository 接口和 MongoTemplate 两种操作模式。本文覆盖配置、基础 CRUD、复杂查询、聚合与事务。
1. 配置
# application.yml
spring:
data:
mongodb:
uri: mongodb://user:pass@mongo1:27017,mongo2:27017/mydatabase?replicaSet=rs0
# 或:
# host: localhost
# port: 27017
# database: mydatabase
# username: user
# password: pass
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
2. 实体映射
@Document(collection = "products")
@CompoundIndex(name = "category_price", def = "{'category': 1, 'price': -1}")
public class Product {
@Id
private String id; // 映射 _id
private String name;
private String category;
private BigDecimal price;
private int stock;
@Field("created_at")
private Instant createdAt;
@DBRef
private Supplier supplier; // 引用(慎用,性能差)
// 嵌套文档
private List<Review> reviews;
}
public record Review(String userId, int rating, String comment, Instant date) {}
3. Repository 接口
public interface ProductRepository extends MongoRepository<Product, String> {
// 自动派生查询
List<Product> findByCategoryAndPriceLessThan(String category, BigDecimal price);
// 模糊搜索(正则)
List<Product> findByNameContainingIgnoreCase(String name);
// 排序分页
Page<Product> findByCategoryOrderByPriceDesc(String category, Pageable pageable);
// @Query 自定义
@Query("{ 'category': ?0, 'price': { $gte: ?1, $lte: ?2 } }")
List<Product> findByPriceRange(String category, BigDecimal min, BigDecimal max);
// 聚合统计
@Aggregation(pipeline = {
"{ $match: { category: ?0 } }",
"{ $group: { _id: null, avgPrice: { $avg: '$price' }, totalStock: { $sum: '$stock' } } }"
})
ProductStats getStatsByCategory(String category);
}
4. MongoTemplate
@Service
public class ProductService {
@Autowired private MongoTemplate mongoTemplate;
public List<Product> search(String keyword, String category) {
Query query = new Query();
// 动态条件
if (StringUtils.hasText(keyword)) {
query.addCriteria(Criteria.where("name")
.regex(keyword, "i"));
}
if (StringUtils.hasText(category)) {
query.addCriteria(Criteria.where("category").is(category));
}
query.with(Sort.by(Sort.Direction.DESC, "createdAt"));
query.limit(20);
return mongoTemplate.find(query, Product.class);
}
// 批量更新
public void updateStockBatch(Map<String, Integer> stockChanges) {
BulkOperations bulkOps = mongoTemplate.bulkOps(
BulkOperations.BulkMode.UNORDERED, Product.class);
stockChanges.forEach((id, qty) -> {
Query query = Query.query(Criteria.where("_id").is(id));
Update update = new Update().inc("stock", qty);
bulkOps.updateOne(query, update);
});
bulkOps.execute();
}
// 聚合管道
public List<Document> getCategoryRevenue() {
Aggregation agg = Aggregation.newAggregation(
Aggregation.match(Criteria.where("status").is("completed")),
Aggregation.unwind("items"),
Aggregation.group("items.category")
.sum(ArithmeticOperators.Multiply.valueOf("items.price")
.multiplyBy("items.quantity")).as("revenue"),
Aggregation.sort(Sort.Direction.DESC, "revenue")
);
return mongoTemplate.aggregate(agg, "orders", Document.class)
.getMappedResults();
}
}
5. 事务
@Service
public class OrderService {
@Autowired private MongoTemplate mongoTemplate;
@Autowired private MongoTransactionManager transactionManager;
@Transactional
public void createOrder(OrderRequest request) {
// 扣减库存
mongoTemplate.updateFirst(
Query.query(Criteria.where("sku").is(request.sku())),
new Update().inc("stock", -request.qty()),
Product.class
);
// 创建订单
Order order = new Order(request);
mongoTemplate.save(order);
}
}
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。