如何将Mongoose模型的_id字段设为Number并自动生成序号
解决Mongoose中_id从ObjectId改为自增Number的问题
只在Schema里声明_id: Number不会生效,因为Mongoose默认会自动生成ObjectId作为_id,且不会自动填充数字类型的序号值。要实现自增数字_id,需要借助计数器集合来保证序号的连续性和原子性,具体步骤如下:
1. 创建计数器集合
这个集合用来记录每个业务集合的当前最大序号,避免并发场景下出现重复序号:
const counterSchema = new mongoose.Schema({ _id: { type: String, required: true }, // 存储对应业务集合的名称 seq: { type: Number, default: 0 } // 当前序号值 }); const Counter = mongoose.model('Counter', counterSchema);
2. 在目标模型中添加自增逻辑
通过pre('save')钩子,在保存新文档前自动获取并递增序号,赋值给_id:
const mySchema = new mongoose.Schema({ _id: { type: Number, required: true } // 这里添加你的其他字段 }); mySchema.pre('save', async function(next) { // 仅处理新增文档的情况 if (this.isNew) { try { // 原子性更新计数器:不存在则创建,存在则序号+1 const counter = await Counter.findOneAndUpdate( { _id: 'MyModel' }, // 替换为你的模型对应的集合名称 { $inc: { seq: 1 } }, { new: true, upsert: true } ); // 将递增后的序号赋值给当前文档的_id this._id = counter.seq; next(); } catch (err) { next(err); } } else { next(); } }); const MyModel = mongoose.model('MyModel', mySchema);
注意事项
- 若业务集合已有数据,需先手动初始化计数器的
seq值为现有文档的最大_id,避免序号冲突 - 不要手动给
_id赋值,否则会覆盖钩子的自增逻辑 findOneAndUpdate的原子性操作能保证多并发场景下不会出现重复序号
内容的提问来源于stack exchange,提问作者Ankur Kumar
相关产品推荐
相关产品推荐

