Spring Boot+MongoDB:如何通过书名查询关联的评论?
解决Spring Boot + MongoDB通过书名查询对应书籍评论的问题
问题分析
你的核心问题在于:Reviews集合中的book字段是DBRef类型,仅存储了指向books集合的文档ID和集合名称,并非内嵌完整的Books对象。因此你之前定义的findByBooksNameContainsIgnoreCase方法无法生效——MongoDB无法直接从Reviews文档中读取到book.name这个字段。
解决方案
下面提供两种可行的实现方式,无需修改数据库结构:
方式一:分两次查询(简单易实现)
先通过书名匹配到对应的书籍ID,再根据ID查询关联的评论。
完善BookRepository
添加根据书名模糊查询的方法:public interface BookRepository extends MongoRepository<Books, String> { // 模糊匹配书名,忽略大小写 List<Books> findByNameContainsIgnoreCase(String name); }修改ReviewsRepository
添加根据书籍ID查询评论的方法:public interface ReviewsRepository extends MongoRepository<Reviews, String> { // 根据书籍ID集合批量查询评论 List<Reviews> findByBookIdIn(List<String> bookIds); }注意:确保你的Reviews实体类中,
book字段标注了@DBRef,且Books实体类有对应的getId()方法。调整Controller逻辑
@RestController public class ReviewController { @Autowired private BookRepository bookRepository; @Autowired private ReviewsRepository reviewsRepository; @PostMapping("/reviews/searchbybook") public List<Reviews> searchReviewsByBookName(@RequestBody Books book) { // 1. 查询所有匹配书名的书籍 List<Books> matchedBooks = bookRepository.findByNameContainsIgnoreCase(book.getName()); if (matchedBooks.isEmpty()) { return Collections.emptyList(); } // 2. 提取书籍ID,查询关联评论 List<String> bookIds = matchedBooks.stream() .map(Books::getId) .collect(Collectors.toList()); return reviewsRepository.findByBookIdIn(bookIds); } }
方式二:使用MongoDB聚合查询(更高效)
通过聚合查询直接关联两个集合,一次数据库请求完成查询,适合数据量较大的场景。
使用MongoTemplate实现聚合
@Autowired private MongoTemplate mongoTemplate; public List<Reviews> searchReviewsByBookName(String bookName) { Aggregation aggregation = Aggregation.newAggregation( // 关联books集合:用Reviews的book.$id匹配Books的_id Aggregation.lookup("books", "book.$id", "_id", "matchedBook"), // 过滤书名匹配的结果,忽略大小写 Aggregation.match(Criteria.where("matchedBook.name") .regex(Pattern.compile(bookName, Pattern.CASE_INSENSITIVE))), // 移除临时生成的matchedBook字段,返回原始评论结构 Aggregation.project().andExclude("matchedBook") ); // 执行聚合查询,映射为Reviews对象列表 AggregationResults<Reviews> results = mongoTemplate.aggregate(aggregation, "reviews", Reviews.class); return results.getMappedResults(); }Controller调用
@PostMapping("/reviews/searchbybook") public List<Reviews> searchReviewsByBookName(@RequestBody Books book) { return searchReviewsByBookName(book.getName()); }
关键说明
- DBRef在MongoDB中仅作为引用存在,不会自动展开关联数据,因此无法直接通过关联对象的属性进行查询。
- 聚合查询的方式减少了数据库交互次数,性能更优,但代码复杂度略高;分两次查询的方式更直观,适合快速开发。
内容的提问来源于stack exchange,提问作者alwaysneedhelp1901
相关产品推荐
相关产品推荐

