You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中Mongoose pre-save钩子失效问题排查与解决求助

Mongoose pre-save钩子不生效问题排查与解决(NestJS环境)

问题根源分析

  1. 钩子绑定时机错误:你是在mongoose.model()创建模型之后,才给Schema添加pre-save钩子。Mongoose生成模型时会固化Schema的所有配置,后续添加的钩子不会被模型应用。
  2. Model名称大小写不匹配:Schema中定义的模型名是GenieJourney,但Module里MongooseModule.forFeatureAsync配置的name是Geniejourney(小写j),导致Nest无法正确关联模型与Schema。
  3. 业务实现方式可优化:pre-save钩子仅在save()方法触发时生效,无法覆盖update()等批量操作,用数据库层面的复合唯一索引实现「特定公司内topic唯一」更可靠。

解决方案

步骤1:修正钩子绑定时机

将pre-save钩子移到创建模型之前,确保Schema绑定钩子后再生成模型:

// schema.ts
export const GenieJourneySchemaProvider = {
  provide: 'GenieJourney',
  useFactory: (): mongoose.Model => {
    // 先给Schema绑定pre-save钩子
    GenieJourneySchema.pre('save', async function(next) {
      const targetCompanyId = '66cc605febff3c565065d17b';
      if (this.companyId.toString() === targetCompanyId) {
        // 用this.constructor代替直接引用model,避免作用域问题
        const existingTopic = await this.constructor.findOne({ 
          companyId: targetCompanyId, 
          topic: this.topic, 
          __deletedAt__: null 
        });
        if (existingTopic) {
          return next(new Error('Topic must be unique within the company.'));
        }
      }
      next();
    });
    // 再基于绑定好钩子的Schema创建模型
    return mongoose.model('GenieJourney', GenieJourneySchema);
  }
}

步骤2:统一Model名称大小写

修改module.ts中MongooseModule.forFeatureAsync的name,与Schema定义的模型名保持一致:

// module.ts
@Module({
  imports: [
    HttpModule,
    MongooseModule.forFeatureAsync([
      { 
        name: 'GenieJourney', // 修正为和Schema一致的名称
        useFactory: GenieJourneySchemaProvider.useFactory
      }
    ])
  ],
  providers: [GenieJourneyService, GenieJourneySchemaProvider],
  controllers: [GenieJourneyController],
  exports: [MongooseModule],
})
export class GenieJourneyModule {}

步骤3:推荐用数据库索引实现业务需求(更可靠)

如果要实现所有公司内topic+companyId+__deletedAt__的唯一性,直接添加复合唯一索引,数据库层面的约束不会漏掉任何操作(包括批量更新):

// schema.ts
const GenieJourneySchema = new Schema(
  // 原有字段定义...
)
  .index({ companyId: 1, name: 1, __deletedAt__: 1 }, { unique: true })
  // 新增:仅对未软删除的文档,校验companyId+topic的唯一性
  .index({ companyId: 1, topic: 1, __deletedAt__: 1 }, { 
    unique: true, 
    partialFilterExpression: { __deletedAt__: null } 
  })
  .plugin(beautifyUnique, {
    message: '{PATH} 已存在 ({VALUE})',
  });

内容的提问来源于stack exchange,提问作者Ravi kant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 04:17:47