NestJS TypeScript中MongoDB文档更新报错及代码优化咨询
问题原因与解决方案
核心问题:then的错误使用
你当前代码中then的用法有误——你直接将insertOne(...)作为参数传给then,这会导致insertOne在deleteOne还未执行完成时就立即调用,而非等待删除操作结束后执行。这就是偶尔出现**_id重复崩溃**的根本原因:原文档尚未被删除,新插入的文档携带相同的_id,触发MongoDB的唯一键约束冲突。
解决方案1:修正then链式调用(满足你的await改then、移除o=o[0]需求)
以下是调整后的代码,通过正确的Promise链式调用确保执行顺序,同时直接在then中处理查询结果:
this.getOrder(orderId) // 直接在then回调中获取第一个订单,无需单独赋值 .then(orders => { const targetOrder = orders[0]; if (!targetOrder) { throw new Error(`Order with ID ${orderId} does not exist`); } // 删除完成后,将目标订单传递给下一个then return db.collection('orders').deleteOne({ orderId }) .then(() => targetOrder); }) // 确保删除完成后再执行插入 .then(targetOrder => { return db.collection('orders').insertOne({ ...targetOrder, active: false, shopId: shopId }); }) // 统一处理所有错误,避免崩溃 .catch(error => { console.error('Failed to process order:', error); // 根据业务需求添加错误处理逻辑,如返回错误响应 });
解决方案2:使用原子更新(更优方案)
实际上,你不需要通过"删除再插入"的方式修改文档,MongoDB的updateOne是原子操作,能避免并发问题且性能更优:
// 无需先查询订单,直接执行原子更新 db.collection('orders').updateOne( { orderId }, { $set: { active: false, shopId: shopId } } ) .then(updateResult => { if (updateResult.matchedCount === 0) { throw new Error(`Order with ID ${orderId} does not exist`); } console.log('Order updated successfully'); }) .catch(error => { console.error('Failed to update order:', error); });
如果需要先确认订单存在再更新,也可以保留查询步骤:
this.getOrder(orderId) .then(orders => { if (!orders[0]) { throw new Error(`Order with ID ${orderId} does not exist`); } return db.collection('orders').updateOne( { orderId }, { $set: { active: false, shopId: shopId } } ); }) .catch(error => { console.error('Failed to update order:', error); });
关键说明
updateOne操作是原子性的,同一时间只会有一个修改操作作用于目标文档,彻底避免了_id冲突的风险。- 链式调用中,务必将异步操作放在
then的回调函数内,而非直接传入操作结果,这样才能保证执行顺序。
内容的提问来源于stack exchange,提问作者HMT
相关产品推荐
相关产品推荐

