Search code examples
typescriptmongoosenestjsmongoose-schemadto

how to manage timestamps in schema in nestjs without explicitly defining createdAt,updatedAt


I am working with Mongoose in NestJS and having an issue regarding timestamps in the user.schema.ts file given below. here typescript doesn't know about createdAt,updatedAt.

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

interface TimeStamps {
  createdAt: Date;
  updatedAt: Date;
}

@Schema({ versionKey: false, timestamps: true })
export class User extends Document implements TimeStamps {
  @Prop({ required: true })
  firstName: string;

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

  @Prop({ required: true, unique: true })
  email: string;

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

  @Prop({ enum: ['admin', 'user'], default: 'user' })
  role: string;
}

export const UserSchema = SchemaFactory.createForClass(User);

Here I am having an error saying:

Class 'User' incorrectly implements interface 'TimeStamps'. Type 'User' is missing the following properties from type 'TimeStamps': createdAt, updatedAt ts(2420)

I am using timestamps in my get-user.dto.ts file to expose/allow them to be sent to clientside. I want to tell typescript there are updatedAt and createdAt properties but without explicitly defining them in the schema. How can I achieve that?

Even if I extend User from Document (imported from Mongoose) it doesn't know about createdAt and updatedAt. I see this error on functions return types where I define the return type as GetUserDto and function which is returning User. do not match.

here is GetUserDto

import { Expose, Transform } from 'class-transformer';

export class GetUserDto {
  @Expose()
  @Transform(({ obj }) => obj._id)
  _id?: string;

  @Expose()
  firstName: string;

  @Expose()
  lastName: string;

  @Expose()
  email: string;

  @Expose()
  role: string;

  @Expose()
  createdAt: Date;

  @Expose()
  updatedAt: Date;
}

and now the findUser code is:

@ApiOperation({ summary: 'Get user' })
@HttpCode(HttpStatus.OK)
@Get(':_id')
findOne(@Param() { _id }: MongoIdDto): Promise<GetUserDto> {
  return this.usersService.findOne({ _id });
}

here while returning from the findOne function. I am getting the error:

Type 'Promise<Document<unknown, {}, User> & User & { _id: ObjectId; }>' is not assignable to type 'Promise'. Type 'Document<unknown, {}, User> & User & { _id: ObjectId; }' is missing the following properties from type 'GetUserDto': createdAt, updatedAt


Solution

  • the solution I found is to add timestamps true in the schema options and also add createdAt, and updatedAt as schema properties. in this way, mongoose will update the updatedAt prop itself.

    @Schema({
      versionKey: false,
      timestamps: true,
      validateBeforeSave: true,
    })
    class User extends Document {
      @Prop({ required: true })
      firstName: string;
    
      @Prop({ required: true })
      lastName: string;
    
      @Prop({ required: true, unique: true })
      email: string;
    
      @Prop({ required: true })
      password: string;
    
      @Prop({ enum: ['admin', 'user'], default: 'user' })
      role: string;
    
      @Prop({ default: Date.now })
      createdAt: Date;
    
      @Prop({ default: Date.now })
      updatedAt: Date;
    }