Mongoose邮政编码子串匹配查询返回空结果问题排查
问题分析与修复
你的查询逻辑完全写错了——当前代码是在给每个条件定义一个新的yearSubstring字段,而不是做前缀匹配判断,MongoDB自然找不到符合条件的文档。
错误原因
你生成的$or数组结构是这样的:
[ { yearSubstring: { $substr: ["$postalCode", 0, 3] } }, { yearSubstring: { $substr: ["$postalCode", 0, 3] } } ]
这不是查询条件,而是聚合投影的语法,MongoDB会去寻找本身带有yearSubstring字段且值等于对应子串的Job文档,显然你的Job集合里没有这个字段,所以返回空。
修复方案
有三种可靠的实现方式,按需选择:
方案1:$expr结合$or做前缀匹配
给每个用户的邮政编码生成一个表达式条件,直接判断Job的邮政编码前缀是否匹配:
const matchConditions = user.searchFilter.data.map(item => { const postalCode = item.postalCode; return { $expr: { $eq: [ { $substr: ["$postalCode", 0, postalCode.length] }, postalCode ] } }; }); let jobs = await Job.find({ $or: matchConditions });
方案2:正则表达式匹配(更简洁)
直接为每个用户的邮政编码生成前缀正则,MongoDB原生支持正则匹配:
const regexConditions = user.searchFilter.data.map(item => { // 转义正则特殊字符,避免语法错误 const escapedCode = item.postalCode.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); return { postalCode: new RegExp(`^${escapedCode}`) }; }); let jobs = await Job.find({ $or: regexConditions });
方案3:结合国家匹配(更严谨)
如果需要限制只匹配同国家的Job,在条件里加上国家筛选:
const regexConditions = user.searchFilter.data.map(item => { const escapedCode = item.postalCode.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); return { postalCode: new RegExp(`^${escapedCode}`), country: item.country }; }); let jobs = await Job.find({ $or: regexConditions });
额外修正点
- 原代码中
if (!job)判断错误:Job.find()返回的是数组,空数组也是[],不会是null/undefined,应该改成if (jobs.length === 0)。
修正后的完整代码(以正则+国家匹配为例):
const regexConditions = user.searchFilter.data.map(item => { const escapedCode = item.postalCode.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); return { postalCode: new RegExp(`^${escapedCode}`), country: item.country }; }); let jobs = await Job.find({ $or: regexConditions }); if (jobs.length === 0) { return res.status(204).json({ error: "No Data" }); } return res.status(200).send(jobs);
内容的提问来源于stack exchange,提问作者TheCoderGuy
相关产品推荐
相关产品推荐

