TypeORM-NestJS多元素查询与多对多关联实体过滤问题
在NestJS中用TypeORM实现多对多关联的精准多分类过滤
问题场景
需要通过URL参数/books?categories=action,adventure筛选同时属于所有指定分类的书籍,但当前代码仅支持单分类过滤,使用orWhere会返回符合任一分类的结果,无法满足"同时匹配全部分类"的需求;且原代码中重复使用同一参数名导致后续条件覆盖前序,返回结果仅保留最后一个分类的关联数据。
核心问题
- 同一参数名
:category被重复赋值,后续条件会覆盖前序参数值; - 直接对单条分类关联记录使用
andWhere,要求单条分类记录同时匹配多个分类名称,逻辑矛盾(单条分类记录仅对应一个分类)。
解决方案
要实现"同时匹配所有指定分类",需要通过分组+统计匹配分类数量的方式验证:筛选出关联分类包含所有指定项的书籍,具体步骤如下:
1. 定义请求参数DTO
首先在GetBooksQueryDto中声明分类参数,用于接收URL传入的筛选条件:
// get-books-query.dto.ts export class GetBooksQueryDto { title?: string; categories?: string; }
2. 修改查询逻辑
更新books.service.ts中的findAll方法,通过分组和HAVING子句实现精准过滤:
async findAll(query: GetBooksQueryDto): Promise<Book[]> { const booksQuery = this.booksRepository.createQueryBuilder('book'); // 左连接分类表,保留书籍的所有分类关联 booksQuery.leftJoinAndSelect('book.category', 'category'); // 标题模糊过滤(保留原有逻辑) if (query.title) { booksQuery.andWhere('book.title LIKE :title', { title: `%${query.title}%` }); } // 多分类精准过滤逻辑 if (query.categories) { const categoryList = query.categories.split(','); // 匹配所有属于指定分类之一的关联记录 booksQuery.andWhere('category.name IN (:...categories)', { categories: categoryList }); // 按书籍ID分组,统计匹配的分类数量等于传入的分类总数 booksQuery.groupBy('book.id') .having('COUNT(DISTINCT category.name) = :categoryCount', { categoryCount: categoryList.length }); } return booksQuery.getMany(); }
代码逻辑说明
category.name IN (:...categories):匹配所有属于指定分类集合的关联记录;groupBy('book.id'):按书籍主键分组,聚合同一书籍的所有分类关联数据;COUNT(DISTINCT category.name) = :categoryCount:确保当前书籍匹配到的分类数量与传入的分类数量完全一致,即同时包含所有指定分类。
验证结果
请求/books?categories=action,adventure后,将返回同时属于这两个分类的书籍,且完整返回所有关联的分类信息:
[ { "id": 1, "title": "Love is war", "description": "One piece is real", "thumbnail": "file://", "created_at": "2022-11-20T16:36:11.000Z", "updated_at": "2022-11-20T16:36:11.000Z", "category": [ { "id": 1, "name": "action" }, { "id": 2, "name": "adventure" } ] } ]
内容的提问来源于stack exchange,提问作者Imboyo
相关产品推荐
相关产品推荐

