如何在Nest JS中实现动态筛选?商用应用多字段需求
动态多字段筛选实现方案(基于NestJS + TypeORM)
你的现有代码硬编码了筛选字段和查询条件,新增字段就得修改代码,完全没法适配动态多字段的需求,而且where数组的写法会产生OR逻辑,大概率不是你要的筛选效果(应该是价格范围和其他字段的AND组合)。下面是重构后的实现方案:
重构Service层代码
用TypeORM的QueryBuilder来动态构建查询条件,不用逐一指定字段:
public async filtering(filterParams: any) { // 创建查询构建器,指定表别名 const queryBuilder = this.announsRepo.createQueryBuilder('announ'); // 分离价格范围参数和其他筛选字段 const { pricee, priceEnd, ...otherFilters } = filterParams; // 处理价格范围的三种情况 if (pricee && priceEnd) { queryBuilder.andWhere('announ.price BETWEEN :pricee AND :priceEnd', { pricee, priceEnd }); } else if (pricee) { queryBuilder.andWhere('announ.price >= :pricee', { pricee }); } else if (priceEnd) { queryBuilder.andWhere('announ.price <= :priceEnd', { priceEnd }); } // 动态遍历所有其他筛选字段,自动添加查询条件 Object.entries(otherFilters).forEach(([key, value]) => { // 过滤空值,避免无效查询 if (value !== undefined && value !== null && value !== '') { // 默认精确匹配,如需模糊搜索可改为 LIKE :${key} 并设置value为 `%${value}%` queryBuilder.andWhere(`announ.${key} = :${key}`, { [key]: value }); } }); // 执行查询获取结果 const result = await queryBuilder.getMany(); return { filterParams, result }; }
优化建议
1. 用DTO替代any,增强类型安全
创建filter.dto.ts定义筛选参数的类型,避免any带来的类型风险:
export class FilterDto { pricee?: number; priceEnd?: number; place?: string; used?: boolean; currency?: string; publishedAt?: Date; field1?: string; field2?: string; field3?: string; // 后续新增字段直接在这里添加即可 }
然后修改Controller的参数类型:
@ApiOperation({ summary: "筛选" }) @Get('getFiltered') public async filtering( @Query() filterParams: FilterDto ) { return this.announsService.filtering(filterParams); }
2. 扩展字段匹配逻辑
如果某些字段需要特殊处理(比如日期范围、模糊搜索),可以在遍历的时候加判断:
Object.entries(otherFilters).forEach(([key, value]) => { if (!value) return; switch(key) { case 'publishedAt': // 比如只筛选发布日期早于指定时间的内容 queryBuilder.andWhere('announ.publishedAt <= :publishedAt', { publishedAt: value }); break; case 'field1': // 模糊匹配示例 queryBuilder.andWhere('announ.field1 LIKE :field1', { field1: `%${value}%` }); break; default: // 默认精确匹配 queryBuilder.andWhere(`announ.${key} = :${key}`, { [key]: value }); } });
3. 添加分页支持
如果数据量较大,建议加上分页参数:
public async filtering(filterParams: any) { const queryBuilder = this.announsRepo.createQueryBuilder('announ'); // 提取分页参数,默认第一页每页10条 const { page = 1, limit = 10, pricee, priceEnd, ...otherFilters } = filterParams; // ...价格范围和其他字段处理逻辑 // 添加分页 queryBuilder.skip((page - 1) * limit).take(limit); const result = await queryBuilder.getMany(); // 可以额外返回总条数 const total = await queryBuilder.getCount(); return { filterParams, result, total }; }
内容的提问来源于stack exchange,提问作者Sharl Shaboyan
相关产品推荐
相关产品推荐

