
本文介绍如何使用 mongoose 正确获取集合中文档总数,并基于该数值生成递增 id,避免因误用 `findone()` 导致的 `nan` 错误。
在构建类似“猜 Emoji”这类需要唯一序号标识(如关卡 ID、题目 ID)的应用时,开发者常希望通过“当前文档总数 + 1”来生成新文档的自增 ID。但直接调用 model.findOne() 并对其结果取 .length 是典型误区:findOne() 返回的是单个文档对象(或 null),而非数组,因此 data.length 实际访问的是对象上不存在的 length 属性,结果为 undefined,再参与 +1 运算即得 NaN。
✅ 正确做法是使用 Mongoose 提供的聚合计数方法:
// ✅ 推荐:countDocuments() —— 安全、高效、支持查询条件 const count = await model.countDocuments(); // 返回 Promiseconst newID = count + 1; await model.create({ ID: newID, /* 其他字段 */ });
⚠️ 注意事项:
- ❌ 避免使用已废弃的 model.count()(无参数时行为不一致,且不推荐);
- ✅ countDocuments() 是 MongoDB 4.0+ 推荐方式,精确统计匹配文档数,支持过滤条件(如 countDocuments({ status: 'active' }));
- ⚠️ 若需严格保证 ID 全局唯一且连续(如竞赛编号),注意并发写入场景下 count + 1 可能引发竞态条件(两个请求同时读到相同 count 值)。生产环境建议改用 MongoDB 的 ObjectId、自动递增插件(如 mongoose-auto-increment),或通过原子操作(如 findOneAndUpdate 配合 $inc 在计数器集合中维护)实现线程安全自增。
? 小结:findOne() 用于查单条数据,countDocuments() 才是统计数量的正确 API。牢记语义差异,可避免多数基础性 NaN 和逻辑错误。










