NestJs Nested Document In MongoDB

Yadollah khaje hosseini
3 min readJun 27, 2021

--

insert nested document in mongoose(Date field not work):

In Model:

@Schema()

export class ReceptionTime {

@Prop({type: Date})

startTime: Date;

@Prop({type: Date})

callTime: Date;

@Prop({type: Date})

endTime: Date;

}

export const receptionTimeObjectSchema=SchemaFactory.createForClass(ReceptionTime);

@Schema()

export class Reception {

@Prop({type: receptionTimeObjectSchema})

// @ValidateNested() @Type(() => ReceptionTime)

receptionTimes: ReceptionTime;

}

export const ReceptionSchema = SchemaFactory.createForClass(Reception);

In Dto:

export class ReceptionTime {

@IsOptional()

@IsDateString()

startTime: Date;

@IsOptional()

@IsDateString()

callTime: Date;

@IsOptional()

@IsDateString()

endTime: Date;

}

export class CreateReceptionDto {

@ValidateNested() @Type(() => ReceptionTime)

@IsOptional()

receptionTimes: ReceptionTime;

}

Example 2:

addressUser.schema.ts

import {Prop, Schema, SchemaFactory} from "@nestjs/mongoose";
import {AddressEnum} from "../../common/enums/general.enum";

@Schema()
export class AddressUser{

@Prop()
countryId:string;

@Prop()
provinceId:string;

@Prop()
cityId:string;

@Prop()
address:string;

@Prop()
postalCode:string;

@Prop({type:String,enum:AddressEnum})
type:string;

@Prop({default:Date()})
createdAt: Date;

@Prop({default:Date()})
updatedAt: Date;

}

export const addressUserObjectSchema = SchemaFactory.createForClass(AddressUser);

addressUserObjectSchema.pre('save', function (next) {
let addressUser = this as any;
const now = new Date();
if (!addressUser.createdAt) {
addressUser.createdAt = now;
}
addressUser.updatedAt = now;
next();
});

addressUser.type.ts

import {IsDateString, IsEnum, IsMongoId, IsNotEmpty, IsNumber, IsOptional, IsString} from "class-validator";
import {AddressEnum} from "../../common/enums/general.enum";

export class AddressUserType {
@IsOptional()
@IsMongoId()
countryId:string;

@IsOptional()
@IsMongoId()
provinceId:string;

@IsOptional()
@IsMongoId()
cityId:string;

@IsNotEmpty()
@IsString()
address:string;

@IsOptional()
@IsString()
postalCode:string;

@IsNotEmpty()
@IsEnum(AddressEnum)
type:string;

@IsOptional()
@IsDateString()
createdAt:string;

@IsOptional()
@IsDateString()
updatedAt:string;

}

user.model.ts

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

import * as bcrypt from 'bcrypt';

import {ActivationEnum, AddressEnum, GenderEnum, MaritalEnum} from "../../common/enums/general.enum";
import {MobileType} from "../types/mobile.type";
import {PhoneType} from "../types/phone.type";
import {ServiceType} from "../types/service.type";
import {SpouseType} from "../types/spouse.type";
import {AddressUser, addressUserObjectSchema} from "../schemas/addressUser.schema";

export type UserDocument = User & Document;

export class UserRes extends Document {
mobile:string;
}


@Schema()
export class User extends Document {

@Prop()
mobileCountryId: string;

@Prop()
mobile:string;

@Prop()
countryId: string;

@Prop({type:String,enum:GenderEnum})
gender: string;

@Prop()
firstName: string;


@Prop()
lastName: string;


@Prop()
fatherName: string;

@Prop()
username: string;

@Prop()
password: string;


@Prop()
nationalCode: string;

@Prop()
identityCode: string;

@Prop({type:String,enum:ActivationEnum})
status:string;

@Prop()
email: string;

@Prop()
roles: [string];

@Prop({type: MobileType})
mobiles:MobileType[];

@Prop({type: Number})
birthCertificateId: number;

@Prop()
dateOfBirth: Date;

@Prop({type: [addressUserObjectSchema]})
addresses: AddressUser[];

@Prop({type:PhoneType})
phones: PhoneType[];

@Prop({type:String,enum:MaritalEnum})
maritalStatus: string;

@Prop({type:SpouseType})
spouses: SpouseType[];


@Prop()
placeOfIssueCityId: string;


@Prop()
placeOfBirthCityId: string;

@Prop()
referralWayId: string;

@Prop()
referrerUserId: string;


@Prop()
referrerFullName: string;


@Prop()
referrerAddress: string;


@Prop({type:ServiceType})
services: ServiceType[];

@Prop()
createdAt: Date;

@Prop({required: false})
updatedAt: Date;

@Function()
checkPassword: Function;

@Function()
checkOldPassword: Function;

}

export const UserSchema = SchemaFactory.createForClass(User);

UserSchema.methods.checkPassword = async function (attempt, callback) {
let user = this;
bcrypt.compare(attempt, user.password, (err, isMatch) => {
if (err) return callback(err);
callback(null, isMatch);
});
};

UserSchema.methods.checkOldPassword = function (attempt, callback) {
let user = this;
// console.log('check model:',attempt)
// console.log('check model user password:',user.password)
bcrypt.compare(attempt, user.password, (err, isMatch) => {
if (err) return callback(err);
callback(null, isMatch);
});
};

UserSchema.pre('save', function (next) {
let user = this as any;

//UpdatedAt and CreatedAt
const now = new Date();
if (!user.createdAt) {
user.createdAt = now;
}
user.updatedAt = now;

//PASSWORD and ActivationCode
// Generate a salt and use it to hash the user's password
// user.password = Math.floor(Math.random() * (9999 - 1000)) + 1000;

// bcrypt.genSalt(10, (err, salt) => {
// if (err) return next(err);
// bcrypt.hash(user.password.toString(), salt, (err, hash) => {
// if (err) return next(err);
// user.password = hash;
// next();
// });
// });
next();
});

create-user.dto.ts

import {
IsString,
IsNotEmpty,
Length,
IsOptional,
isAlphanumeric,
IsAlphanumeric,
IsNumber,
Validate, IsArray, IsMongoId, IsEnum, IsEmail, ValidateNested, IsDate, IsDateString
} from 'class-validator';
import {ActivationEnum, GenderEnum, MaritalEnum} from "../../common/enums/general.enum";
import {Type} from 'class-transformer';
import {MobileType} from "../types/mobile.type";
import {AddressUserType} from "../types/addressUser.type";
import {PhoneType} from "../types/phone.type";
import {ServiceType} from "../types/service.type";
import {SpouseType} from "../types/spouse.type";
import {NationalCode} from "../decorators/NationalCode.decorators";



export class CreateUserDto {

@IsMongoId()
@IsNotEmpty()
mobileCountryId: string;

@IsString()
@IsNotEmpty()
@Length(11, 11)
mobile:string;

@IsMongoId()
@IsNotEmpty()
countryId: string;

@IsNotEmpty()
@IsEnum(GenderEnum)
gender: string;

@IsNotEmpty()
@IsString()
firstName: string;

@IsNotEmpty()
@IsString()
lastName: string;

@IsString()
@IsNotEmpty()
fatherName: string;



@IsString()
@IsOptional()
username: string;

@IsString()
@IsOptional()
@Length(6)
password: string;

@IsString()
@IsOptional()
@NationalCode({message:"NationalCod is Invalid"})
nationalCode: string;

@IsString()
@IsOptional()
@Length(8)
identityCode: string;

@IsEnum(ActivationEnum)
status:string;


@IsOptional()
@IsEmail()
email:string

@IsNotEmpty()
@IsArray()
roles: []

@IsArray()
@IsOptional()
@ValidateNested() @Type(() => MobileType)
mobiles:MobileType[];

@IsOptional()
@IsNumber()
birthCertificateId: number;

@IsDateString()
dateOfBirth: Date;

@IsOptional()
@IsOptional()
@ValidateNested() @Type(() => AddressUserType)
addresses: AddressUserType[];

@IsOptional()
@ValidateNested() @Type(() => PhoneType)
phones: PhoneType[];

@IsEnum(MaritalEnum)
maritalStatus: string;

@IsOptional()
@IsMongoId()
placeOfIssueCityId: string;

@IsOptional()
@IsMongoId()
placeOfBirthCityId: string;

@IsOptional()
@IsMongoId()
referralWayId: string;

@IsMongoId()
@IsOptional()
referrerUserId: string;

@IsOptional()
@IsString()
referrerFullName: string;

@IsOptional()
@IsString()
referrerAddress: string;

@IsOptional()
@ValidateNested() @Type(() => ServiceType)
services: ServiceType[];



@IsOptional()
@ValidateNested() @Type(() => SpouseType)
spouses: SpouseType[];

@IsOptional()
@IsString()
spouseCountryId: string;

@IsOptional()
@IsString()
spouseFirstName: string;

@IsOptional()
@IsString()
spouseLastName: string;

@IsOptional()
@IsString()
spouseFatherName: string;

@IsOptional()
@IsString()
spouseNationalCode: string;

@IsOptional()
@IsString()
spouseIdentityCode: string;

@IsOptional()
@IsDateString()
dateOfMarriage:Date;

@IsOptional()
@IsDateString()
spouseDateOfBirth:Date;



}

--

--