如何在 Mongoose 中准确统计文档数量并实现自增 ID

本文介绍如何使用 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(); // 返回 Promise
const 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 和逻辑错误。