
本文介绍如何正确获取 mongodb 集合中文档总数,并基于该数值生成唯一、递增的 id,避免因误用 `findone()` 导致 `nan` 错误。
在构建类似“猜 Emoji”这类需要序号标识(如题号、关卡 ID)的应用时,开发者常希望通过统计已有文档数量来生成下一个自增 ID(例如:第 1 条记录 ID 为 1,新增后为 2)。但若错误地使用 model.findOne() 并对其结果调用 .length,会得到 undefined 或 NaN——因为 findOne() 返回的是单个文档对象(Object),而对象没有 .length 属性(数组才有),Object.length 恒为 undefined,参与数学运算即转为 NaN。
✅ 正确做法是使用 Mongoose 提供的聚合安全、高性能的计数方法:
// ✅ 推荐:使用 countDocuments()(推荐用于带条件或未来兼容性) const count = await model.countDocuments(); // 返回 Promiseconst newId = count + 1; await model.create({ ID: newId });
⚠️ 注意事项:
- ❌ 不要使用已弃用的 model.count()(Mongoose 7+ 中已移除),它易受查询条件影响且不支持 Promise 默认返回;
- ✅ countDocuments() 是当前标准方法,支持链式查询(如 countDocuments({ status: 'active' })),且准确反映实际匹配文档数;
- ⚠️ 在高并发场景下,countDocuments() + create() 非原子操作,存在极小概率 ID 冲突(如两个请求同时读到 count=5,均写入 ID=6)。如需强一致性 ID,建议:
- 使用 MongoDB 原生 ObjectId(默认 _id 已具备时间序与唯一性);
- 或引入独立计数器集合(通过 findOneAndUpdate(..., { upsert: true, new: true }) 实现原子自增);
- 或改用数据库自增字段(如 PostgreSQL)或 Redis 序列器。
? 总结:findOne() 返回单文档对象,不可取 .length;统计文档数请始终使用 await model.countDocuments(),再进行逻辑计算。简洁、可靠、符合 Mongoose 最佳实践。










