Sequelize(Node.js)中enum与integer字段Like搜索的类型转换方法
解决Sequelize中Enum/Integer字段使用Like操作符的类型转换问题
这个问题我之前也碰到过,本质是PostgreSQL(从错误提示能看出来你用的是PG数据库)不允许直接对enum或integer类型的字段使用like/iLike操作符,必须先把这些字段显式转换为text类型才行。下面给你两种实用的解决办法,结合你的现有代码来修改:
方法1:用Sequelize内置的cast+col函数(推荐,更安全)
这种方式符合Sequelize的ORM风格,还能自动处理参数绑定,避免SQL注入风险。首先需要引入Sequelize的相关工具:
const { Op, Sequelize, cast, col } = require('sequelize');
然后修改你的查询条件里的enum和integer字段:
- 对于enum类型的
job.status,把原来的like条件改成用Sequelize.where结合cast转换的写法 - 对于integer类型的
job.jobReferenceId,同样转成text后再用iLike
修改后的完整whereCondn如下:
const searchValue = search || ''; whereCondn = { [Op.or]:[ // 处理integer类型的jobReferenceId Sequelize.where(cast(col('job.jobReferenceId'), 'TEXT'), Op.iLike, searchValue), { '$job.jobTitle$': { [Op.iLike]: `%${searchValue}%` } }, { '$job.experienceLevel$': { [Op.iLike]: `%${searchValue}%` } }, { '$job.location$': { [Op.iLike]: `%${searchValue}%` } }, // 处理enum类型的status Sequelize.where(cast(col('job.status'), 'TEXT'), Op.like, `%${searchValue}%`), { '$job->hospital.name$':{ [Op.iLike]: `%${searchValue}%` } }, { '$job->grade.gradeName$':{ [Op.iLike]: `%${searchValue}%` } }, { '$job->speciality.specialityName$':{ [Op.iLike]: `%${searchValue}%` } }, { '$job->specialityService.serviceName$':{ [Op.iLike]: `%${searchValue}%` } } ], [Op.and]:[ { '$job.draft$' : false }, { 'doctorId' : bodyInput['doctorId'] } ] };
方法2:用literal写原生SQL片段(灵活适合复杂场景)
如果你更熟悉原生PostgreSQL语法,可以直接用Sequelize.literal写类型转换的SQL:
const searchValue = search || ''; whereCondn = { [Op.or]:[ // integer类型转text后做iLike { [Op.iLike]: Sequelize.literal(`"job"."jobReferenceId"::TEXT ILIKE '${searchValue}'`) }, { '$job.jobTitle$': { [Op.iLike]: `%${searchValue}%` } }, { '$job.experienceLevel$': { [Op.iLike]: `%${searchValue}%` } }, { '$job.location$': { [Op.iLike]: `%${searchValue}%` } }, // enum类型转text后做like { [Op.like]: Sequelize.literal(`"job"."status"::TEXT LIKE '%${searchValue}%'`) }, { '$job->hospital.name$':{ [Op.iLike]: `%${searchValue}%` } }, { '$job->grade.gradeName$':{ [Op.iLike]: `%${searchValue}%` } }, { '$job->speciality.specialityName$':{ [Op.iLike]: `%${searchValue}%` } }, { '$job->specialityService.serviceName$':{ [Op.iLike]: `%${searchValue}%` } } ], [Op.and]:[ { '$job.draft$' : false }, { 'doctorId' : bodyInput['doctorId'] } ] };
注意事项
- 用
literal的时候要小心SQL注入风险,如果你的search参数来自用户输入,最好用参数绑定的方式:// 示例:绑定参数避免注入 { [Op.like]: Sequelize.literal(`"job"."status"::TEXT LIKE '%' || :searchVal || '%'`) } // 然后在查询的options里加上replacements: replacements: { searchVal: searchValue } - 两种方法选哪种都行,
cast+col的方式更贴合Sequelize的最佳实践,推荐优先使用。
内容的提问来源于stack exchange,提问作者Sheema
相关产品推荐
相关产品推荐

