如何优雅捕获Node.js项目中的MongoDB写入异常
先说一个核心判断:insertMany 写入失败时,并不会抛出一个统一的错误类型。你可能会遇到 MongoWriteConcernError、MongoBulkWriteError、MongoServerError(比如 code 11000 代表重复键),甚至原生 Error(网络中断)。关键不在于看 error.name,而是要盯住 error.code 和 error.writeErrors——对于批量写入来说,后者尤其重要。

写入失败时 insertMany 抛什么错误?
实际上,MongoDB 驱动会根据具体失败原因返回不同错误对象:写关注没满足,给你 MongoWriteConcernError;批量写入中部分失败,给你 MongoBulkWriteError;常规服务端错误如重复键,则是带 code: 11000 的 MongoServerError;当然还有网络中断这种原生 Error。所以判断逻辑要围绕 error.code 和 error.writeErrors 展开,别只盯着 error.name——它往往不靠谱。
为什么 try/catch 捕不到“控制台没输出”?
这种情况十有八九是变量名引用问题。举个例子:你明明用 const Model = require("./models/match") 导入,结果在路由里写了 await Match.insertMany(...)。那好,Match is not defined 这个 ReferenceError 在函数刚开始执行时就被抛出了——同步语法错误,try/catch 根本抓不住,因为整个 async 函数体还没走到 await 那一行,当然不会有任何输出。
所以检查顺序很简单:
- 核对模型中使用的变量名和
require时定义的名字是否完全一致,大小写、拼写都不能马虎。 - 确认模型已正确导出,没有丢三落四。
- 在
catch块里加上console.error(error.stack)而不是只打印error.message——堆栈信息能告诉你错在哪一行。
insertMany 部分失败时怎么拿到具体哪几条错了?
insertMany 默认走 ordered: true,即遇到第一条错误就立刻刹车。但只要改成 ordered: false,它就会继续处理剩余数据,最后通过 error.writeErrors 数组把每条失败项的索引、错误码和详情全抛给你:
try { const result = await Model.insertMany(data, { ordered: false });} catch (error) { if (error.writeErrors) { error.writeErrors.forEach(({ index, code, errmsg }) => { console.warn(`第 ${index} 条数据写入失败(code ${code}):`, errmsg); }); }}
这里有几个常见错误码值得记住:
code: 11000—— 唯一键冲突,解决方法通常是去重,或者改用updateOne配合upsert。code: 121—— 文档验证失败,回头看看 schema 里的required和validate规则是不是太严了。- 另外,
ordered: false虽然不影响成功写入的数据,但错误堆栈会明显变长,生产环境最好加上日志采样,免得被海量错误信息刷屏。
事务中写入失败,commitTransaction 还会执行吗?
答案是否定的。commitTransaction 只有在显式调用时才会触发,而一旦某次 collection.insertOne 失败并抛出异常,驱动会自动 abort 当前事务,commitTransaction 那行代码根本执行不到。所以你能拿到错误码的地方只有两个:要么是 CRUD 操作本身(比如 insertOne 报 code: 133 写冲突),要么是显式调用 commitTransaction 时(可能报 code: 112 或 251)。
- 千万不要在
catch里默认事务已经提交——老老实实检查session.inTransaction()的状态。 - 注意
code: 112并不代表写冲突(写冲突是133),它更可能意味着会话过期或事务超时。这时候要结合error.errorLabels?.includes('TransientTransactionError')来判断能否重试。 - 如果事务内某个操作因为
maxTimeMS设置太短而超时,错误码是code: 50(MaxTimeMSExpired),这发生在具体命令层,可不是 commit 阶段的问题。
说到这里,核心结论就很清晰了:事务写入异常的根因往往不在 commit 那一刻,而在你第一次调用 insertOne 或 updateMany 的瞬间。错误码早就藏在那里了,别等到 commitTransaction 才去找原因。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
配置Java应用支持Oracle数据库AD/Kerberos身份验证
配置Java应用支持OracleAD Kerberos需正确设置JVM的krb5 conf与jaas conf,JDBCURL添加oracle net authentication_services=(KERBEROS5)并与SPN严格匹配。AD用户需映射为Oracle企业用户并授予CREATESESSION权限。SPN注册和EUS映射是常见故障点。
Redis订阅者BGSAVE期间响应变慢:RDB持久化IO影响分析
Redis订阅者在BGSAVE期间响应变慢,源于fork阻塞、COW内存争抢及磁盘I O高负载三重叠加。通过将RDB迁移至从节点、禁用THP、调整swappiness并手动触发避开高峰,可有效降低对主服务的影响。
如何优雅捕获Node.js项目中的MongoDB写入异常
批量插入失败时不会抛出统一错误类型,需关注错误代码和写入错误数组。部分失败时可设置有序参数为假以获取写入错误数组。事务中写入失败会自动中止事务,提交事务不会执行。常见错误码11000为唯一键冲突,121为文档验证失败。
如何用SQL窗口函数ROW_NUMBER实现分组内去重
行号函数仅分配行序号,不能直接去重。需通过子查询或公用表表达式过滤行号为1的行,实现分组内去重。若排序字段有重复,应加入唯一键以保证排序稳定性。还需注意不同数据库对空值排序的差异及版本兼容性。
Spring Boot RedisTemplate无法直接注入?检查泛型声明是否正确
RedisTemplate注入失败多因泛型擦除导致类型不匹配,需保证配置类返回类型、注入字段类型及内部key value类型三者一致。避免使用无泛型或通配符形式,不同序列化策略应定义独立Bean并用@Qualifier区分。StringRedisTemplate为独立Bean,不可混用。
- 日榜
- 周榜
- 月榜
相关攻略
2026-07-08 07:04
2026-07-08 07:03
2026-07-08 07:03
2026-07-08 07:03
2026-07-08 07:03
2026-07-08 07:02
2026-07-08 07:02
2026-07-08 07:02
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

