NodeJS+MongoDB实现自增ID及Promise问题排查
解决MongoDB自增主键实现中的Promise异步问题
你遇到的核心问题是MongoDB Node.js驱动的异步方法被当作同步代码处理了——findOneAndUpdate返回的是一个Promise对象,而非直接的更新后文档,所以直接访问ret.seq会拿到undefined或者抛出错误。下面是完整的修正方案:
第一步:重构自增序列函数为异步函数
async function getNextSequence(name) { // 注意:新版MongoDB驱动中returnNewDocument已废弃,改用returnDocument: 'after' const updateResult = await db.collection('counters').findOneAndUpdate( { _id: name }, { $inc: { seq: 1 } }, { returnDocument: 'after', // 指定返回更新后的文档 upsert: true // 可选:计数器不存在时自动创建,避免首次调用报错 } ); return updateResult.value.seq; // findOneAndUpdate的结果嵌套在value字段中 }
第二步:异步调用自增函数并插入文档
因为getNextSequence现在是异步函数,调用它必须用await,所以插入逻辑也要放在异步上下文里:
async function insertSMSRecord(record) { try { const smsId = await getNextSequence("sms_id"); const insertResult = await db.collection('SMS').insertOne({ "_id": smsId, ...record // 展开传入的记录字段 }); console.log(`SMS记录插入成功,ID为${smsId}`); return insertResult; } catch (err) { console.error("插入或获取序列失败:", err); throw err; // 向上抛出错误方便上层处理 } } // 调用示例 insertSMSRecord({ phone: "138xxxx1234", content: "验证码xxxx" });
关键注意点
- 替换废弃参数:
returnNewDocument已被新版驱动弃用,改用returnDocument: 'after'确保拿到更新后的计数器值。 - 自动创建计数器:添加
upsert: true后,首次调用时会自动生成{_id: "sms_id", seq: 1}的计数器文档,避免报错。 - 错误处理:所有异步操作都包裹在
try/catch中,防止未捕获的Promise异常导致程序崩溃。 - 环境要求:确保你的代码运行在支持
async/await的Node.js环境(Node.js 8及以上版本即可)。
内容的提问来源于stack exchange,提问作者fudge
相关产品推荐
相关产品推荐

