Search code examples
node.jsmongodbmongoosenestjscustomvalidator

Getting "Error while querying template: TypeError: Cannot read properties of undefined (reading 'findOne')"


I'm trying to use one of my MongoDB models in a custom validator class in my nest js application. My models are defined inside a folder called "model". I'm using InjectModel of mongoose to use the model in my class. This approach worked in my service file. But it is not working in my custom validation file. My schema definition is like this :

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { HydratedDocument } from 'mongoose';

export type TemplateDocument = HydratedDocument<Template>;

@Schema()
export class Template {
  @Prop({ required: true })
  name: string;

  @Prop({ required: true })
  content: string;

  @Prop({ required: true })
  path: string;

  @Prop({ required: false })
  isSelected: boolean;
}

export const TemplateSchema = SchemaFactory.createForClass(Template);

Inside my module file I'm importing the template schema as below:

import { Module } from '@nestjs/common';
import { TemplateController } from './template.controller';
import { TemplateService } from './template.service';
import { MongooseModule } from '@nestjs/mongoose';
import { Template, TemplateSchema } from 'src/models/template';

@Module({
  imports: [
    MongooseModule.forFeature([
      { name: Template.name, schema: TemplateSchema },
    ]),
  ],
  controllers: [TemplateController],
  providers: [TemplateService],
})
export class TemplateModule {}

My custom validation class is inside the same folder "Template" but on a child directory. This is my custom class

import {
  registerDecorator,
  ValidationOptions,
  ValidatorConstraint,
  ValidatorConstraintInterface,
} from 'class-validator';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Template } from '../../../../models/template';
import { Injectable } from '@nestjs/common';

@ValidatorConstraint({ async: true })
@Injectable()
export class IsTemplateNotExist implements ValidatorConstraintInterface {
  constructor(
    @InjectModel(Template.name) private templateModel: Model<Template>,
  ) {}

  async validate(name: string): Promise<boolean> {
    try {
      console.log('this.templateModel = ', this.templateModel);
      const template = await this.templateModel.findOne({ name }).exec();
      console.log('template = ', template);
      return template === null; // Use null instead of undefined
    } catch (error) {
      console.error('Error while querying template:', error);
      return false; // Handle the error case appropriately
    }
    // return this.templateModel.findOne({ name }).then((template) => {
    //   console.log('tempate = ', template);
    //   return template === undefined;
    // });
  }
}

export function TemplateNotExist(validationOptions?: ValidationOptions) {
  return function (object: object, propertyName: string) {
    registerDecorator({
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      constraints: [],
      validator: IsTemplateNotExist,
    });
  };
}

But on the validate method this.templateModel is undefined I don't know the cause of this issue. Thanks in advance for helping. I'm new to nest js and mongodb.


Solution

  • I got the solution to my question from the suggestions that stack overflow shows before posting my question. The question that gave me the answer was actually not the one that I was asking, but on seeing that I got the answer. So I thought I should post my question along with the answer so that it will help others..

    Actually, on my module file, I forgot to specify the IsTemplateNotExist class as a provider. My updated module file look like this:

    import { Module } from '@nestjs/common';
    import { TemplateController } from './template.controller';
    import { TemplateService } from './template.service';
    import { MongooseModule } from '@nestjs/mongoose';
    import { Template, TemplateSchema } from 'src/models/template';
    import { IsTemplateNotExist } from './validations/templateNotExist.rule';
    
    @Module({
      imports: [
        MongooseModule.forFeature([
          { name: Template.name, schema: TemplateSchema },
        ]),
      ],
      controllers: [TemplateController],
      providers: [TemplateService, IsTemplateNotExist],
    })
    export class TemplateModule {}