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

使用Mongoose findOneAndUpdate插入非重复文档时手机号为null的问题

解决MongoDB findOneAndUpdate upsert时phoneNumber为null的问题

看起来你遇到的问题是在使用findOneAndUpdate配合upsert: true插入新文档时,phoneNumber字段被存成了null,我来帮你分析下原因并给出解决方案。

问题根源分析

你的代码里有两个关键问题可能导致这个情况:

  1. bodymen验证未正确配置:路由里的body({ phoneNumber })没有明确验证规则,可能导致请求中的phoneNumber没有被正确解析,甚至在验证失败时直接传递了undefined到后续逻辑;
  2. findOneAndUpdate的参数逻辑:当upsert: true且查询条件中的phoneNumber为undefined时,MongoDB会把undefined转化为null存入数据库,加上你用$set再次设置phoneNumber: body.phoneNumber,相当于把字段强制设为null。

分步解决方案

1. 完善bodymen的验证规则

首先要确保请求中的phoneNumber被正确捕获且符合要求,修改路由的验证配置:

router.post('/login', body({ 
  phoneNumber: {
    type: String,
    required: true, // 强制要求该字段存在
    trim: true // 可选:去除首尾空格
  } 
}), login)

2. 优化Login函数的逻辑

在执行数据库操作前,先检查phoneNumber是否有效,同时简化findOneAndUpdate的更新参数(因为upsert时,查询条件会自动带入新文档,不需要重复$set相同字段):

export const login = ({ bodymen: { body } }, res, next) => {
  // 前置检查:确保phoneNumber存在
  if (!body.phoneNumber) {
    return res.status(400).json({ error: 'phoneNumber是必填字段' });
  }

  return Login.findOneAndUpdate(
    { phoneNumber: body.phoneNumber },
    {}, // 因为是匹配phoneNumber,更新操作可以为空(如果仅需要插入或无更新需求)
    { 
      new: true, 
      upsert: true,
      runValidators: true // 重要:确保upsert时也遵守Schema的验证规则
    }
  )
  .then((login) => login.view(true))
  .then(success(res, 201))
  .catch(next);
};

3. 确认Login模型的Schema配置

检查你的Login模型,确保phoneNumber字段的类型和约束正确,避免默认值为null:

const mongoose = require('mongoose');
const LoginSchema = new mongoose.Schema({
  phoneNumber: {
    type: String,
    required: true,
    unique: true // 可选:如果需要确保每个手机号唯一
  }
});

module.exports = mongoose.model('Login', LoginSchema);

额外说明

如果你需要在upsert时同时设置其他字段,可以在findOneAndUpdate的第二个参数里添加,比如:

{ $set: { lastLoginTime: new Date() } }

这样既会插入phoneNumber(来自查询条件),又会设置lastLoginTime字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 20:57:26