Mongoose 如何实现文档id属性默认自动赋值为其_id值
Mongoose 让自定义id字段自动等于文档自身_id的实现方案
完全可以通过Schema层配置实现单数据库操作搞定需求,不需要沿用“创建后赋值再保存”的两步流程。最符合Mongoose设计规范的实现方式,是利用前置保存中间件在文档写入前自动完成id字段赋值。
常见实现误区
- 直接给id字段设静态默认值行不通:Mongoose的默认值会在文档实例化阶段计算,这时候文档自身的_id还未生成,根本拿不到当前文档的_id值,要么生成的id和自身_id不一致,要么直接报错。
- Mongoose默认内置的虚拟id字段不满足需求:这个虚拟字段不会真正存储到数据库中,也无法绑定唯一索引,和你要的可持久化、带唯一约束的id属性不是一回事。
推荐实现:pre-save中间件一次写入
注意修正原Schema中字段间遗漏的逗号语法问题,完整可运行的配置如下:
const modelSchema = new Schema( { id: { type: String, unique: true }, property_1: { type: String, unique: false }, property_2: { type: String, unique: false } // 其他业务字段 }, { // 关闭Mongoose内置的虚拟id字段,避免和自定义实字段冲突 id: false } ); // 注册保存前置钩子 modelSchema.pre('save', function (next) { // 仅在新建文档、且id字段未手动赋值时执行逻辑 if (this.isNew && !this.id) { // 将自身_id转为字符串赋值给id字段,保证二者完全一致 this.id = this._id.toString(); } next(); }); const Model = mongoose.model('YourModel', modelSchema);
这个方案的核心逻辑是:钩子会在文档触发保存动作、真正向MongoDB发起写入请求之前执行,自动把当前文档的_id值转成字符串赋值给自定义的id字段,整个流程只需要一次数据库写入,完全替代原有的两步操作。
对应的业务代码也不需要做额外改造,直接正常调用创建接口即可:
// 全程只有一次数据库写入操作 Model.create({ property_1: 'value_1', property_2: 'value_2' }).then((document) => { // 此时返回的文档已经携带了正确的id值,和自身_id完全相等 console.log(document.id === document._id.toString()); // 输出 true });
相比原有两步操作的优势
- 没有额外的数据库开销:不需要创建完文档后再拉取、修改、二次保存,整个写入流程只有一次请求。
- 避免并发一致性问题:原有方式在第一次create插入空id文档时,因为id字段有唯一索引,并发场景下很容易出现空值冲突、或者写入脏数据(比如第一次create成功、第二次save失败,就会留下一个id为空的无效文档);新方式在第一次写入时就已经带上了合法的、全局唯一的id值,从根本上避免这类问题。
- 逻辑解耦:id的赋值规则完全封装在Schema层,业务代码不需要关心id的生成逻辑,所有创建、保存文档的场景都会自动遵守这个规则,不会出现漏赋值的情况。
内容的提问来源于stack exchange,提问作者NeNaD
相关产品推荐
相关产品推荐

