You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ExpressJS路由中MongoDB数字类型手机号前缀匹配搜索问题

Number类型手机号前缀匹配搜索解决方案

问题背景

JobApplication集合中mobile_no字段为Number类型,当前仅支持精确匹配完整手机号,无法通过前缀(如"67")搜索到以该前缀开头的号码(如67890),需保留Number类型实现前缀搜索。


方法1:使用$expr实现实时字符串转换匹配

适合数据量较小的场景,通过MongoDB聚合表达式将Number类型转为字符串后做前缀匹配:

修改路由代码

router.get('/job_applications', async (req, res) => {
    try {
        let query = {};
        const { name, email, mobile_no } = req.query;
        
        if (name) {
            query.name = { $regex: name, $options: 'i' };
        }
        
        if (email) {
            query.email = { $regex: email, $options: 'i' };
        }

        // 修改mobile_no的查询逻辑
        if (mobile_no && !isNaN(Number(mobile_no))) {
            const prefix = mobile_no.toString();
            query.$expr = {
                $regexMatch: {
                    input: { $toString: "$mobile_no" },
                    regex: `^${prefix}`,
                    options: ''
                }
            };
        }

        const job_applications = await JobApplication.find(query);
        res.render('./admin/job_applications/job_app_home', { 
            job_applications, 
            noResults: job_applications.length === 0, 
            params: req.query 
        });
    } catch (err) {
        console.error(err);
        res.status(500).send('Server Error');
    }
});

方法2:新增字符串副本字段(性能优先推荐)

数据量较大时,方法1会触发全表扫描,性能低下。可新增字符串类型字段存储手机号的字符串形式,专门用于搜索:

1. 修改JobApplication Schema

const jobApplicationSchema = new mongoose.Schema({
    name: {
      type: String,
      required: true
    },
    email: {
      type: String,
      required: true
    },
    mobile_no: {
      type: Number,
      required: true
    },
    // 新增字符串类型的手机号字段
    mobile_str: {
      type: String,
      required: true
    },
    resume: {
      type: String,
      required: true
    },
    job_title: {
      type: String
    }
  }, { timestamps: true });

2. 添加预保存中间件自动同步字段

在Schema定义后添加中间件,确保新增/修改数据时自动同步mobile_str:

jobApplicationSchema.pre('save', function(next) {
    this.mobile_str = this.mobile_no.toString();
    next();
});

3. 迁移已有数据

执行以下脚本更新已有文档的mobile_str字段:

// 在项目中执行一次该脚本
const JobApplication = require('./path/to/your/models').JobApplication;

async function migrateMobileNumbers() {
    try {
        await JobApplication.updateMany(
            {}, 
            [ { $set: { mobile_str: { $toString: "$mobile_no" } } } ]
        );
        console.log('数据迁移完成');
    } catch (err) {
        console.error(err);
    }
}

migrateMobileNumbers();

4. 修改路由查询逻辑

router.get('/job_applications', async (req, res) => {
    try {
        let query = {};
        const { name, email, mobile_no } = req.query;
        
        if (name) {
            query.name = { $regex: name, $options: 'i' };
        }
        
        if (email) {
            query.email = { $regex: email, $options: 'i' };
        }

        if (mobile_no && !isNaN(Number(mobile_no))) {
            const prefix = mobile_no.toString();
            query.mobile_str = { $regex: `^${prefix}`, $options: '' };
        }

        const job_applications = await JobApplication.find(query);
        res.render('./admin/job_applications/job_app_home', { 
            job_applications, 
            noResults: job_applications.length === 0, 
            params: req.query 
        });
    } catch (err) {
        console.error(err);
        res.status(500).send('Server Error');
    }
});

注意事项

  • EJS模板代码无需修改,保持原有的表单和列表渲染逻辑即可
  • 方法2中可给mobile_str字段添加索引,进一步提升搜索性能:
    jobApplicationSchema.index({ mobile_str: 1 });
    

内容的提问来源于stack exchange,提问作者Afzal Hamdulay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:15:56