Search code examples
typescriptmongoosenestjs

not able to use pre save mongoose hook in nestJs


I have an use case in which before saving a document I need to check if the document is a valid document to be saved based on condition.

To deal with it I am trying to use pre save mongoose hook. But I am doing something wrong because of which it is not working.

I am beginner in NestJs, please help me identify and resolve the problem. I will be highly thankful for any help.

This is the schema.ts file-

import mongoose, { Schema } from 'mongoose';
import * as beautifyUnique from 'mongoose-unique-validator';
import { GenieGames, Status } from 'src/common/globalEnums.enums';

const GenieJourneySchema = new Schema(
  {
    name: {
      type: String,
    },
    userId: {
      type: String,
    },
    companyId: {
      type: Schema.Types.ObjectId,
      ref: 'Companies',
      required: true,
    },
    __deletedAt__: {
      type: Date,
      default: undefined,
    },
    topic: {
      type: String,
    }
    
)
  .index({ companyId: 1, name: 1, __deletedAt__: 1 }, { unique: true })
  .plugin(beautifyUnique, {
    message: 'Journey name exists ({VALUE})',
  });


export const GenieJourneySchemaProvider = {
  provide: 'GenieJourney',
  useFactory: (): Promise<void> => {

    const model = mongoose.model('GenieJourney', GenieJourneySchema);

    GenieJourneySchema.pre('save', async function(next) {
      const companyId = '66cc605febff3c565065d17b';

      if (this.companyId.toString() === companyId) {
        const existingTopic = await model.findOne({ companyId: companyId, topic: this.topic, __deletedAt__: null });

        if (existingTopic) {
          return next(new Error('Topic must be unique within the company.'));
        }
      }

      next();
    });
    return;
  }
}

The following is the module.ts file where I am configuring the schema-

@Module({
  imports: [
    HttpModule,
    MongooseModule.forFeatureAsync([
      { name: 'Geniejourney', 
        useFactory: GenieJourneySchemaProvider.useFactory
      }
    ])
  ],
  providers: [GenieJourneyService, GenieJourneySchemaProvider],
  controllers: [GenieJourneyController],
  exports: [MongooseModule],
})
export class GenieJourneyModule {
}

I have tried various approaches but none works. I am expecting that I should be able to create genieJourney with unique topic inside a specific company.


Solution

  • You are complicating stuff too much. It is best to use the NestJS mongoose wrapper (@nestjs/mongoose).

    Please take a look at the user model in my NestJS starter project.

    https://github.com/tivanov/nestjs-angular-starter/blob/master/backend/src/users/model/user.model.ts

    I am using a class with decorators to define the schema and then the built-in SchemaFactory to generate the schema provider. This will take care of everything for you.

    Then, just add the pre save listener and you should be good to go.

    To 'register' the model, just provide the schema provider. Take a look at https://github.com/tivanov/nestjs-angular-starter/blob/master/backend/src/users/users.module.ts for the Users model example.