升级Mongoose至5.0.13后,angular-fullstack应用出现Bluebird相关500错误
解决Mongoose 5升级后更新操作抛500错误的问题
这个问题我之前帮人排查过,本质是Mongoose 5.x对更新类方法的返回值和行为做了不少改动,而angular-fullstack生成的代码还是沿用了Mongoose 4的写法,导致代码处理返回值时出现「expecting an arr...」这类数组相关的错误。
核心原因
Mongoose 4和5在更新方法(比如update、findByIdAndUpdate、bulkWrite)的返回值结构上差异很大:
- Mongoose 4中,部分更新方法会返回文档数组或者旧文档;
- Mongoose 5中,这类方法默认返回的是操作结果对象(比如
WriteResult、BulkWriteResult),包含nModified、insertedCount等统计属性,不再直接返回文档数组。
而你代码里大概率还在对这些返回值做数组操作(比如判断length、调用forEach),自然会抛出「期望数组」的类型错误。
具体修复步骤
1. 定位报错的更新接口
先找到抛出500错误的API路由代码(比如server/api/xxx/index.js里的update方法),看是用了哪个Mongoose方法导致的。
2. 针对不同更新方法调整代码
这里举几个常见的修复例子:
例子1:findByIdAndUpdate的适配
原来Mongoose 4的写法(默认返回旧文档):
Thing.findByIdAndUpdate(req.params.id, req.body, (err, thing) => { if (err) return handleError(res, err); if (!thing) return res.status(404).send('Not Found'); res.json(thing); });
Mongoose 5中虽然默认返回新文档,但建议显式指定{new: true}确保一致性,同时如果需要验证更新字段,加上runValidators: true:
Thing.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true }) .then(thing => { if (!thing) { return res.status(404).send('Not Found'); } res.json(thing); }) .catch(err => handleError(res, err));
例子2:update/updateOne的适配
原来Mongoose 4用update的写法(可能期望返回数组):
Thing.update({ _id: req.params.id }, req.body, (err, results) => { if (err) return handleError(res, err); if (results.length === 0) return res.status(404).send('Not Found'); res.json(results); });
Mongoose 5中update已被废弃,改用updateOne,并且返回的是操作结果对象,要通过nModified判断是否更新成功:
Thing.updateOne({ _id: req.params.id }, req.body, { runValidators: true }) .then(result => { if (result.nModified === 0) { return res.status(404).send('Not Found'); } // 如果需要返回更新后的文档,额外查询一次 return Thing.findById(req.params.id); }) .then(thing => res.json(thing)) .catch(err => handleError(res, err));
例子3:bulkWrite的适配
如果是bulkWrite相关的错误,注意Mongoose 5返回的是BulkWriteResult对象,不要把它当数组处理:
const operations = [ // 你的批量操作,比如updateOne、insertOne等 ]; Thing.bulkWrite(operations) .then(result => { // 用result里的统计属性判断结果,比如modifiedCount、insertedCount res.json({ success: true, updated: result.modifiedCount, inserted: result.insertedCount }); }) .catch(err => handleError(res, err));
3. 额外注意事项
- Mongoose 5默认启用了
strictQuery,如果你的查询里有schema定义外的字段,会被自动过滤,需要的话可以在schema里设置strictQuery: false; - 检查
handleError函数是否适配Mongoose 5的错误格式,比如错误对象的属性是否有变化; - 所有模型的schema定义,检查是否有Mongoose 5不兼容的选项(比如
required的布尔值写法是兼容的,但部分旧的自定义验证器可能需要调整)。
内容的提问来源于stack exchange,提问作者S. Hussey
相关产品推荐
相关产品推荐

