Node.js+Mongoose+Promise场景下$push数组更新失败问题排查
看起来你遇到的核心问题是MongoDB的$push操作符使用错误,加上findOneAndUpdate的配置选项没设置对,导致数组更新不生效,同时Promise的包裹方式也存在冗余(不过你提到项目要求必须用Promise,我们可以调整成正确的写法)。
1. 最关键的错误:$push的目标字段写错了
在你的db.js的pushsession方法里,你写了:
model.findOneAndUpdate({fb_id: id}, {$push: {data}},{safe: true})
这里的{$push: {data}}等价于{$push: {data: data}}——也就是说你试图往一个名叫data的字段里push数据,但你的usersessionSchema里根本没有这个字段!你的目标字段是message_body,所以必须明确指定它。
2. 第二个问题:findOneAndUpdate默认返回旧文档
默认情况下,mongoose的findOneAndUpdate返回的是更新前的原始文档,而不是更新后的文档。这会导致你在日志里看到的res还是旧数据,误以为更新没生效,同时controller里的判断也会出错。你需要添加{new: true}选项来获取更新后的文档。
3. 可选优化:简化Promise的使用
mongoose的所有CRUD方法本身就返回Promise,你不需要手动再包裹一层new Promise,这样既冗余又容易出错。不过如果项目要求必须保留Promise结构,我们也可以调整成正确的写法。
修正后的代码示例
方案一:简化Promise(推荐,符合async/await风格)
修改db.js里的pushsession方法:
module.exports.pushsession = async (model, id, data) => { try { // 直接使用mongoose返回的Promise,配合async/await const updatedDoc = await model.findOneAndUpdate( { fb_id: id }, // 正确指定要push到message_body数组的内容 { $push: { message_body: data.message_body } }, // 关键选项:返回更新后的文档 { new: true } ); console.log("更新后的文档:", updatedDoc); return updatedDoc; } catch (err) { console.error("更新出错:", err); throw err; } };
方案二:保留手动Promise包裹(满足项目要求)
如果必须手动写Promise,改成这样:
module.exports.pushsession = (model, id, data) => { return new Promise((resolve, reject) => { console.log("要插入的数据:", data); model.findOneAndUpdate( { fb_id: id }, { $push: { message_body: data.message_body } }, // 修正目标字段 { new: true } // 添加此选项获取更新后的数据 ) .then(updatedDoc => { console.log("更新后的文档:", updatedDoc); resolve(updatedDoc); }) .catch(err => { console.error("更新出错:", err); reject(err); }); }); };
额外优化:简化传入的数据结构
你在controller里把要插入的对象包在了message_body里,其实可以直接传这个对象,减少嵌套:
在controller.js里修改request的定义:
var request = { message: req.body.message, message_type: req.body.message_type, timestamp: datetime_now };
然后对应的db.js里的$push改成:
{ $push: { message_body: data } }
这样代码更直观,减少不必要的嵌套。
最后验证点
- 确保请求体里的
fb_id是存在于数据库中的值 - 检查Postman的请求是否正确发送了
message、message_type参数 - 更新后查看数据库里的文档,确认
message_body数组是否新增了元素
内容的提问来源于stack exchange,提问作者Quer

