Mongoose findOneAndUpdate无法更新数据库问题求助
问题描述
数据库结构示例
{ "_id": "xxxxxxxxxxxxxxxxx", "username": "abcd@yahoo.com", "refreshTokens": [ { "refreshToken": "token_example_1", "_id": "xxxxxxxxxxxxxxxxx" } ], "salt": "salted_stuff", "hash": "hashed_stuff", "__v": 1 }
对应的Schema结构
const session = new Schema({ refreshToken: { type: String, default: '', }, }); const userSchema = new Schema({ password: String, refreshTokens: [session], }); userSchema.set('toJSON', { transform: function (doc, ret, options) { delete ret.refreshToken; return ret; }, });
遇到的问题
尝试查找指定refreshToken并更新为新的newRefreshToken(已确认userId和newRefreshToken值正确),但执行后数据库中的refreshToken未更新,且无任何报错。尝试过updateOne方法、简化查询条件写法均未成功;链式调用.then((user) => {user.save()})时,报错提示该方法不存在。数据库连接正常,用户创建功能可正常使用。
问题原因及解决办法
原因1:数组元素更新的查询与更新语法错误
MongoDB更新数组内元素需要使用位置操作符$或数组过滤操作符$[<identifier>],如果直接写refreshTokens.refreshToken而不指定位置,无法定位到具体要更新的数组元素。
解决办法:使用updateOne结合位置操作符
// 正确的updateOne写法 User.updateOne( { _id: userId, "refreshTokens.refreshToken": oldRefreshToken }, { $set: { "refreshTokens.$.refreshToken": newRefreshToken } } ) .then(result => { // 检查是否匹配到文档:result.nModified === 1表示更新成功 console.log(result); }) .catch(err => { console.error(err); });
- 第一个参数的查询条件同时指定用户
_id和数组内的refreshToken,确保定位到正确的用户和对应的数组元素 $操作符会匹配查询条件中第一个符合的数组元素,用$set更新其refreshToken值
原因2:链式调用.save()时拿到的不是Mongoose文档对象
如果使用updateOne,返回的是更新结果对象(不是用户文档),调用.save()自然会报错;如果用findOneAndUpdate且未配置new: true,返回的是更新前的原始文档,也可能导致后续操作异常。
解决办法:用文档实例的save()方法更新
先查询到完整的用户文档,找到对应的数组元素修改后再保存:
User.findOne({ _id: userId }) .then(user => { if (!user) return; // 找到对应的refreshToken元素 const session = user.refreshTokens.find(s => s.refreshToken === oldRefreshToken); if (session) { session.refreshToken = newRefreshToken; return user.save(); // 此时user是Mongoose文档对象,可调用save } }) .then(savedUser => { console.log('更新成功:', savedUser); }) .catch(err => { console.error(err); });
原因3:toJSON转换的误导
你的toJSON转换中删除了ret.refreshToken,但这只会影响文档转JSON时的输出,不会改变数据库中的存储。调试时如果打印user.toJSON(),会看不到refreshToken,但数据库里实际是存在的,不要被这个现象误导。
额外检查点
- 确认
oldRefreshToken的值完全匹配数据库中的值(注意大小写、空格等细节) - 检查是否有其他中间件(如pre/post钩子)拦截了更新操作
- 开启Mongoose调试模式:
mongoose.set('debug', true),查看实际发送给MongoDB的查询语句,排查语法问题
内容的提问来源于stack exchange,提问作者MPiland
相关产品推荐
相关产品推荐

