如何在TypeORM中使用findOptions实现AND与OR组合查询?
需求与问题
目标SQL
想要构建的SQL查询如下:
SELECT * FROM studies WHERE idUser = '12489184291' AND (type LIKE '%something%' OR type LIKE '%something%')
需求是在用户A的所有studies记录中,使用LIKE运算符进行非精确搜索,查找名称或类型以"study for"开头的记录,询问该需求是否可行。
当前代码实现
当前基于TypeORM的代码实现如下:
const searchQuery = getSearchQuery(search, on); const filterQuery = getFilterQueries(filters); req.options = { where: [ ...searchQuery, ...filterQuery, ] } const getSearchQuery = (search: string, on: string) => { if (!search) return []; const searchQuery = `%${search}%`; switch (on) { case 'estudios': return [ { nombre: ILike(searchQuery) }, { tipoModificacion: ILike(searchQuery) }, { antecedentes: ILike(searchQuery) }, { observaciones: ILike(searchQuery) }, ] default: return []; } } const getFilterQueries = (filters: {}) => { let filterObj: any = {}; const urlFilters = new URLSearchParams(filters); urlFilters.forEach((value, key) => { if (key === 'createdAt' || key === 'responseDate') { filterObj = { ...filterObj, ...dateRange(key, value) } return; } else { filterObj[key] = value; } }); if (Object.keys(filterObj).length > 0) { return [filterObj] } else { return []; } };
当前问题:where数组写法默认是全局OR逻辑,无法实现目标SQL的AND+OR混合逻辑,因此提出两个疑问:
- 能否使用findOptions在同一个where中同时实现AND与OR逻辑?
- 还是更推荐使用QueryBuilder?
解答
需求可行性
完全可行,你的目标SQL逻辑是常规的多条件查询场景:通过AND固定用户筛选范围,再用OR组合多个模糊搜索条件,完全可以实现。
方案一:用findOptions实现混合逻辑
TypeORM的findOptions支持嵌套AND/OR操作符,无需依赖数组(数组元素默认是OR关系),通过嵌套结构就能实现需求:
修改代码如下,将搜索条件包装成OR组,再与过滤条件通过AND组合:
const searchQuery = getSearchQuery(search, on); const filterQuery = getFilterQueries(filters); const whereConditions: any[] = []; // 添加过滤条件(如idUser这类全局AND条件) if (filterQuery.length > 0) { whereConditions.push(...filterQuery); } // 添加搜索的OR条件组 if (searchQuery.length > 0) { whereConditions.push({ OR: searchQuery }); } req.options = { where: whereConditions.length > 0 ? whereConditions : undefined };
改造后生成的SQL会自动变成:WHERE (filter条件) AND (nombre LIKE ... OR tipoModificacion LIKE ...),完美匹配你的目标逻辑。
方案二:使用QueryBuilder(推荐复杂场景)
如果后续查询逻辑会变得更复杂(比如多层嵌套条件、关联表查询、聚合函数等),QueryBuilder是更优选择,它能精准控制SQL生成,可读性和扩展性更强:
示例代码:
import { getRepository } from "typeorm"; import { Study } from "./entities/Study"; // 替换为你的实体类 // 构建查询器 const queryBuilder = getRepository(Study).createQueryBuilder('study'); // 处理过滤条件 const filterObj = getFilterQueries(filters)[0]; if (filterObj) { Object.keys(filterObj).forEach(key => { if (key === 'createdAt' || key === 'responseDate') { // 假设dateRange返回{ [key]: Between(start, end) } const { start, end } = filterObj[key]; queryBuilder.andWhere(`study.${key} BETWEEN :start AND :end`, { start, end }); } else { queryBuilder.andWhere(`study.${key} = :${key}`, { [key]: filterObj[key] }); } }); } // 处理搜索的OR条件 const search = ...; // 你的搜索输入值 if (search) { const searchPattern = `%${search}%`; queryBuilder.andWhere(` study.nombre ILIKE :search OR study.tipoModificacion ILIKE :search OR study.antecedentes ILIKE :search OR study.observaciones ILIKE :search `, { search: searchPattern }); } // 执行查询 const result = await queryBuilder.getMany();
总结
- 简单场景:用findOptions的嵌套AND/OR足够满足需求,代码更简洁;
- 复杂场景:推荐使用QueryBuilder,调试和扩展更方便。
内容的提问来源于stack exchange,提问作者Miguel V
相关产品推荐
相关产品推荐

