knex.js执行LIKE模式匹配仅返回精确匹配结果如何解决?
问题根因
你的代码没有给LIKE匹配规则添加SQL通配符,最终生成的执行语句等价于:
SELECT * FROM recipes WHERE LOWER(title) LIKE 'test'
SQL语法中,当LIKE后面的匹配串不带%(匹配任意长度任意字符)、_(匹配单个任意字符)这类通配符时,匹配效果和等值判断=完全一致,因此只会返回title完全等于传入值的记录,无法实现模糊匹配。
修复方法
方法1:修正Raw语句的参数,拼接通配符
把通配符和传入的参数值拼接后再做绑定,不要把通配符直接写在Raw SQL字符串里,避免SQL注入风险:
async function getByTitle(title) { const result = await db('recipes') .select('*') // 两边加%代表匹配title中任意位置包含传入值的记录 .whereRaw('LOWER(title) LIKE ?', [`%${title}%`]); return result; }
如果业务需要匹配「以传入标题开头」的记录,就把参数改成${title}%;如果需要匹配「以传入标题结尾」,就改成%${title}。你当前场景要返回test、test1、test2、test3四条记录,用两边加%的写法即可。
方法2:使用Knex内置查询方法(更推荐)
不需要手写Raw语句,Knex本身对模糊查询有封装,写法更简洁也不容易出语法错误:
// PostgreSQL等支持ilike(大小写不敏感匹配)的数据库可用 async function getByTitle(title) { const result = await db('recipes') .select('*') .where('title', 'ilike', `%${title}%`); return result; }
如果是MySQL、SQLite这类不原生支持ilike的数据库,可以用内置方法统一转义大小写:
// MySQL/SQLite适配写法 async function getByTitle(title) { const result = await db('recipes') .select('*') .whereRaw('LOWER(title) LIKE LOWER(?)', [`%${title}%`]); return result; }
排查步骤
如果修改后仍不符合预期,按以下顺序定位问题:
- 在查询链末尾调用
.toSQL()方法打印Knex实际生成的SQL语句和绑定参数,确认LIKE对应的绑定参数确实携带了%通配符 - 检查入参处理逻辑,确认传入的title参数没有经过特殊字符过滤,导致拼接的
%被提前转义或删除 - 检查数据库字段的排序规则,确认不存在大小写、字符集相关的匹配异常
内容的提问来源于stack exchange,提问作者David Em-Yinn
相关产品推荐
相关产品推荐

