如何使用Regex正则表达式对纯数字类型账户字段实现模糊搜索
问题根因
- 正则查询仅支持MongoDB字符串类型字段,如果你
Account模型里的账号字段定义为Number类型,直接调用regex方法无法返回匹配结果 - 当前使用的正则没有添加开头匹配符
^,会匹配所有包含输入内容的账号,如果你需要实现「输入前几位返回前缀匹配结果」的效果,需要补充前缀匹配规则 - 账号属于标识类数据,即便全为数字也不需要参与数值运算,且长数字(超过16位)用Number存储会存在精度丢失问题,优先建议将
Account模型对应的账号字段类型改为String
修改后代码(字段为String类型场景)
// 正则特殊字符转义方法,避免用户输入特殊字符导致查询异常 function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } router.get('/', async (req, res) => { let query = Account.find() if (req.query.name != null && req.query.name != '') { // 可选:校验输入是否为纯数字,过滤非法查询 const isNumberInput = /^[0-9]+$/.test(req.query.name) if (isNumberInput) { const searchStr = escapeRegExp(req.query.name) // 加^实现前缀匹配,全数字场景不需要忽略大小写可以去掉i参数 query = query.regex('name', new RegExp(`^${searchStr}`)) } } try { const accounts = await query.exec() res.render('accounts/index',{ accounts: accounts, searchOptions: req.query }) } catch(err) { res.redirect('/') } })
不修改字段类型(仍为Number类型)的解决方案
如果不方便修改字段类型,可以用聚合操作把数字字段转为字符串后再匹配:
// 正则特殊字符转义方法,避免用户输入特殊字符导致查询异常 function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } router.get('/', async (req, res) => { let pipeline = [] if (req.query.name != null && req.query.name != '') { const isNumberInput = /^[0-9]+$/.test(req.query.name) if (isNumberInput) { const searchStr = escapeRegExp(req.query.name) pipeline.push({ $addFields: { nameStr: { $toString: "$name" } } }, { $match: { nameStr: { $regex: `^${searchStr}` } } }) } } try { const accounts = await Account.aggregate(pipeline) res.render('accounts/index',{ accounts: accounts, searchOptions: req.query }) } catch(err) { res.redirect('/') } })
内容的提问来源于stack exchange,提问作者Ali Zeeshan
相关产品推荐
相关产品推荐

