How to accept multiple objects into an array NestJS - mongodb

I have a feedbackQuestion schema which takes (title: string, subtitle: string, types: enum, values: enum)
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose'
import { Document } from 'mongoose'
import { Types, Value } from 'src/common/enum/types.enum'
export type FeedbackQuestionDocument = FeedbackQuestion & Document
#Schema({ timestamps: true, id: true })
export class FeedbackQuestion {
#Prop()
title: string
#Prop()
subtitle: string
#Prop()
types: Types
#Prop()
value: Value
}
export const FeedbackQuestionSchema =
SchemaFactory.createForClass(FeedbackQuestion)
The feedbackQuestion schema serves as a subdocument in my feedback schema for the key question
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose'
import mongoose, { Document, ObjectId } from 'mongoose'
import { User } from './user.schema'
import { Transform, Type } from 'class-transformer'
import { FeedbackQuestion } from './feedback-question.schema'
import { distributionChannels } from 'src/common/enum/distributionChannels.enum'
export type FeedbackDocument = Feedback & Document
#Schema({ timestamps: true, id: true })
export class Feedback {
#Transform(({ value }) => value.toString())
_id: ObjectId
#Prop()
label: string
#Prop({ default: false })
status: boolean
#Prop()
question: [FeedbackQuestion]
#Prop()
comment: string
#Prop()
thankYouMessage: string
#Prop()
distributionChannels: distributionChannels
#Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'User' })
#Type(() => User)
user: User
}
export const FeedbackSchema = SchemaFactory.createForClass(Feedback)
when creating my create-feedbackDto, I assigned question to be an array of type feedbackQuestion
import { Type } from 'class-transformer'
import { FeedbackQuestion } from '../../schemas/feedback-question.schema'
import { IsArray, IsEnum, IsNotEmpty, ValidateNested } from 'class-validator'
import { Types, Value } from '../enum/types.enum'
import { distributionChannels } from '../enum/distributionChannels.enum'
export class CreateFeedbackDto {
#IsNotEmpty()
label: string
status: boolean
#IsArray()
#ValidateNested({ each: true })
#Type(() => FeedbackQuestion)
question: FeedbackQuestion[]
#IsNotEmpty()
comment: string
#IsNotEmpty()
thankYouMessage: string
#IsNotEmpty()
title: string
#IsNotEmpty()
subtitle: string
#IsEnum(Types)
#IsNotEmpty()
types: Types
#IsEnum(Value)
#IsNotEmpty()
value: Value
#IsEnum(distributionChannels)
#IsNotEmpty()
distributionChannels: distributionChannels
}
In my feedback services, I want to work on questions such that I can pass in multiple objects of feedbackQuestion into the question array when creating a feedback. Please How can I do that?
The current code only takes one FeedbackQuestion object in the array
import { Injectable } from '#nestjs/common'
import { InjectModel } from '#nestjs/mongoose'
import { Model } from 'mongoose'
import { Feedback, FeedbackDocument } from '../../schemas/feedback.schema'
import {
FeedbackQuestion,
FeedbackQuestionDocument,
} from '../../schemas/feedback-question.schema'
import { IServiceResponse } from '../../common/interfaces/service.interface'
import { CreateFeedbackDto } from 'src/common/dto/create-feedback.dto'
#Inject#5406able()
export class FeedbackService {
constructor(
#Inject#5406Model(Feedback.name)
private feedbackDocumentModel: Model<FeedbackDocument>,
#Inject#5406Model(FeedbackQuestion.name)
private feedbackQuestionDocumentModel: Model<FeedbackQuestionDocument>,
) {}
async createFeedback(payload: CreateFeedbackDto): Promise<IServiceResponse> {
const feedbackQuestion = await this.feedbackQuestionDocumentModel.create({
title: payload.title,
subtitle: payload.subtitle,
type: payload.types,
value: payload.value,
})
const feedback = await this.feedbackDocumentModel.create({
label: payload.label,
status: payload.status,
question: [feedbackQuestion],
comment: payload.comment,
thankYouMesage: payload.thankYouMessage,
distributionChannels: payload.distributionChannels,
})
// feedback.question.push(feedbackQuestion)
await feedback.save()
return {
data: {
user: feedback,
},
}
}
}
This is the current response I get
"label": "Yearly Feedback",
"status": false,
"question": [
{
"title": "Yearly Feedback",
"subtitle": "Rating the Yearly performance of the organization",
"value": 1,
"_id": "627fa9b915d31bbbc0fe6908",
"createdAt": "2022-05-14T13:08:09.180Z",
"updatedAt": "2022-05-14T13:08:09.180Z",
"__v": 0
}
],
Thanks

Related

Enable to set ObjectId in nested array in nest.js

I have a module of question, and I want a structure something like
[ { question: 'REFERENCE ID', answer: { start_value: '1', end_value: '2' } } ],
when I try to save it, it save question id as string but I want to store questionId as ObjectId so I can populate it in other request.
while and the complete response I want is:
{
"answer_by": ObjectId(''), // string, should be user reference ID for populating user
"answers": [
{
"question": ObjectId(''), // string, should be user reference ID for populating question
"answer": {
"start_value": "val1",
"end_value": "val2"
}
}
]
}
here is my schema respectively!
import * as mongoose from "mongoose";
import { Person } from "./person.schema";
import { PostMeetingChecklist, PostMeetingChecklistDocument } from "./post-meeting-checklist.schema";
import { Model, Schema as MongooseSchema } from "mongoose";
import { Resource } from "./resource.schema";
#Schema()
export class Answer {
#Prop()
start_value: string;
#Prop()
end_value: string;
}
#Schema()
export class Item {
#Prop({ type: mongoose.Schema.Types.ObjectId, ref: Question.name})
question: string;
#Prop()
answer: Answer;
}
export type QuestionDocument = Question & mongoose.Document;
#Schema({ timestamps: true })
export class Question {
#Prop({ type: mongoose.Schema.Types.ObjectId, ref: User.name })
answer_by: string;
#Prop()
answers: [Item];
}
export const QuestionSchema = SchemaFactory.createForClass(Question);
in mongoDb,it takes answer_by as ObjectId but question as string, how to fixed that?
Further, I also want to populate this like:
{
"answer_by": User Details,
"answers": [
{
"question": Question Details,
"answer": {
"start_value": "5",
"end_value": "10"
}
}
],
"_id": "63f3146f9f84a58be0b32ad8",
"createdAt": "2023-02-20T06:34:23.300Z",
"updatedAt": "2023-02-20T06:34:23.300Z",
"__v": 0
}
Have tried
#Prop()
answers: [{
question:{
type:mongoose.Schema.Types.ObjectId,
ref:"PostMeetingChecklist"
},
answer: Answer
}];
but in vain.

How to add timestamps fields and _id into nested schema by default

I have a correct schema User where fields _id, createdAt, updatedAt are written by default. But in schema Message it doesn't work.
export type UserDocument = HydratedDocument<User>;
#Schema({ timestamps: true, versionKey: false })
export class Message {
#Prop()
content: string;
}
#Schema({ timestamps: true, versionKey: false })
export class User implements UserInterface {
#Prop()
name: string;
#Prop()
email: string;
#Prop([{ type: mongoose.Schema.Types.ObjectId, ref: 'Message' }])
messages?: Message[];
}
export const UserSchema = SchemaFactory.createForClass(User);
Here is my function of message creating:
async createMessage() {
const user = await this.userModel.findById('63ee4fc044d93a4f6bebf934');
user.messages.push({ content: 'a' });
return await user.save();
}
And error is:
Cast to ObjectId failed for value "{ content: 'a' }" (type Object) at path "messages" because of "BSONTypeError"
But this snippet works fine:
async createUser(createUserDto: CreateUserDto): Promise<CreatedUserDto> {
return this.userModel.findOneAndUpdate(
{ name: createUserDto.name },
createUserDto,
{ upsert: true, new: true },
);
}
How to fix it?
Fixed id, correct implementation:
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
import { HydratedDocument } from 'mongoose';
import { UserInterface } from '../interface/user.interface';
export type UserDocument = HydratedDocument<User>;
#Schema({ timestamps: true, versionKey: false })
export class Message {
#Prop()
content: string;
}
export const MessageSchema = SchemaFactory.createForClass(Message);
#Schema({ timestamps: true, versionKey: false })
export class User implements UserInterface {
#Prop()
name: string;
#Prop()
email: string;
#Prop({ type: [MessageSchema], default: [] })
messages?: Message[];
}
export const UserSchema = SchemaFactory.createForClass(User);

Cannot return null for non-nullable field GraphQL Nestjs

im getting this error Cannot return null for non-nullable field CityBoundaries.city_name. from mongoDB, but if im using static json data, i get my response fine. Here's my code. Any help will be appreciated :)
city-boundries.model.ts
import { ObjectType, Field, ID, Int, Float } from '#nestjs/graphql';
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
import { Document } from 'mongoose';
import 'dotenv/config';
import { CityBoundiresFeatures } from 'src/types/city-boundries-features';
import mongoose from 'mongoose';
export type CityBoundriesDocument = CityBoundaries & Document;
#Schema()
#ObjectType()
export class CityBoundaries extends Document {
#Field(() => ID, { nullable: true })
_id: string | number;
#Prop()
#Field()
readonly city_admin_level: number;
#Prop({ required: true })
#Field()
readonly city_name: string;
#Prop({ required: true })
#Field(() => Float)
readonly city_id: number;
#Prop({ required: true })
#Field(() => Float)
readonly city_osm_id: number;
#Prop({
required: true,
type: mongoose.Schema.Types.ObjectId,
ref: 'CityBoundiresFeatures',
})
#Field(() => [CityBoundiresFeatures], { nullable: true })
features: CityBoundiresFeatures[];
#Prop({ required: true })
#Field({ nullable: true })
type: string;
}
export const CityBoundriesSchema = SchemaFactory.createForClass(CityBoundaries);
city-boundries.module.ts
import { Module } from '#nestjs/common';
import { MongooseModule } from '#nestjs/mongoose';
import {
CityBoundaries,
CityBoundriesSchema,
} from 'src/models/city-boundries.model';
import { CityBoundriesService } from 'src/services/city-boundries.service';
import { CityBoundriesResolvers } from 'src/resolvers/city-boundries.resolver';
import { Bop500_City, CitiesSchema } from 'src/models/cities.model';
import { CitiesService } from 'src/services/cities.service';
#Module({
imports: [
MongooseModule.forFeature([
{
name: CityBoundaries.name,
schema: CityBoundriesSchema,
},
{ name: Bop500_City.name, schema: CitiesSchema },
]),
],
providers: [CityBoundriesService, CityBoundriesResolvers, CitiesService],
})
export class CityBoundriesModule {}
cities.resolver.ts
import { Resolver, Query, Args, ResolveField, Parent } from '#nestjs/graphql';
import { Bop500_City } from 'src/models/cities.model';
import { CityBoundaries } from 'src/models/city-boundries.model';
import { CitiesService } from 'src/services/cities.service';
import { CityBoundriesService } from 'src/services/city-boundries.service';
#Resolver(() => Bop500_City)
export class CitiesResolvers {
constructor(
private readonly citiesService: CitiesService,
private readonly cityBoundariesService: CityBoundriesService,
) {}
#Query(() => [Bop500_City])
/**
* #returns list of all cities
*/
async getAllCities() {
return this.citiesService.findMany();
}
#Query(() => [Bop500_City], { nullable: true })
/**
* #param {string} value take city name as argument from user
* #returns detail of city
*/
async getCity(#Args('city') value: string) {
const res = await this.citiesService.findOneByName(value);
console.log('Response: ', res);
return res;
}
#ResolveField(() => CityBoundaries)
async getBoundries(#Parent() parent: Bop500_City) {
const res = await this.cityBoundariesService.findOneByCityName(
parent.city_name,
);
console.log('Response: ', res);
return res;
}
}
city-boundries.service.ts
import { Injectable } from '#nestjs/common';
import { Model } from 'mongoose';
import { InjectModel } from '#nestjs/mongoose';
import {
CityBoundaries,
CityBoundriesDocument,
} from 'src/models/city-boundries.model';
import * as cityBoundriesData from '../static/City_boundaries.json';
#Injectable()
export class CityBoundriesService {
constructor(
#InjectModel(CityBoundaries.name)
private cityBoundriesModel: Model<CityBoundriesDocument>,
) {}
/**
* #param {string} cityName take city name as argument from user
* #returns boundries of city
*/
async findOneByCityName(cityName: string) {
const res = await this.cityBoundriesModel.find({ city_name: cityName });
return res;
}
}
app.module.ts
import { Module } from '#nestjs/common';
import { GraphQLModule } from '#nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '#nestjs/apollo';
import { MongooseModule } from '#nestjs/mongoose';
import { CitiesModule } from './module/cities.module';
import 'dotenv/config';
import { CityBoundriesModule } from './module/city-boundries.module';
#Module({
imports: [
MongooseModule.forRoot(process.env.MONGODB_DB_URI, {
dbName: process.env.DB_NAME,
}),
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: 'src/schema/schema.gql',
introspection: true,
playground: true,
}),
CitiesModule,
CityBoundriesModule,
],
})
export class AppModule {}

NestJS Mongodb Compoud Index

I am currently writing mongodb schema in nest js.
My schema is below
{
_id: {
filed1: string,
filed2: string,
field3: string,
field4: {
filed5: int
}
}
filed1: ~
...
...
Is there a way to create nestJs schema for the collection?
Is there a way to set the index for the _id field?
I've tried the following, but it didn't work.
import { DateTimeScalar } from '#/common/scalars/dateTime.scalar';
import { Field, Float, ID, Int, ObjectType } from '#nestjs/graphql';
import { Prop, raw, Schema, SchemaFactory } from '#nestjs/mongoose';
import { Document } from 'mongoose';
export type Document = MongooseClass & Document;
#ObjectType()
export class filed4 {
#Field(() => Int)
filed5: number;
}
#ObjectType()
export class compundId {
#Field(() => String)
filed1: string;
#Field(() => String)
filed2: string;
#Field(() => String)
filed3: string;
#Field(() => field4)
field4: field5;
}
#ObjectType()
#Schema({ collection: 'collection' })
export class MongooseClass {
#Field(() => ID, { nullable: false })
#Prop(
raw({
filed1: { type: String },
filed2: { type: String },
filed3: { type: string },
}),
)
_id: compundId;
filed ...
}
const MongooseSchema = SchemaFactory.createForClass(MongooseClass);
MongooseSchema.index({ _id: { filed1: 1, filed5: 1 } });
MongooseSchema.index({ filed2: 1, filed3: 1 });
MongooseSchema.index({ filed5: 1 });
export default ExcuteRateInfoMongooseSchema;
After checking the documentation, I couldn't find an answer to that question. please help me

MissingSchemaError in Nestjs

hello everyone i'm not able specify relation to another model. when i add a relation it's showing me this error
Book Model
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
import { Document } from 'mongoose';
export type BookDocument = Book & Document;
#Schema({ timestamps: true, collection: 'books' })
export class Book {
#Prop({ type: String, required: true })
name: string;
#Prop({ type: String, required: true })
author: string;
#Prop({ type: String, required: true })
bookType: string;
}
export const BooksSchema = SchemaFactory.createForClass(Book);
BookLend Model
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
import { Schema as mongooseSchema, Document } from 'mongoose';
import { Book } from '../../books/enitiy/book.model';
import { IsNotEmpty } from 'class-validator';
export type BookLendDocument = BookLend & Document;
#Schema({ timestamps: true })
export class BookLend {
#IsNotEmpty()
#Prop({ type: mongooseSchema.Types.ObjectId, ref: 'books', required: true })
bookId: Book;
#IsNotEmpty()
#Prop({ type: String, required: true })
name: string;
#IsNotEmpty()
#Prop({ type: String, required: true })
returnDate: string;
#Prop({ type: String })
returnedOn: string;
#IsNotEmpty()
#Prop({ type: String, required: true })
status: string;
}
export const BookLendSchema = SchemaFactory.createForClass(BookLend);
i'm referring the books objectID to booklend booksID , when i use below code i'm getting error MissingSchemaError: Schema hasn't been registered for model "books".
const allBookLendDetails = await this.bookLend
.find()
.populate('bookId')
.exec();
hi guy's I fixed it by importing the BooksSchema into BookLend Module file
here ref code:-
import { Module } from '#nestjs/common';
import { BookLendService } from './book-lend.service';
import { BookLendController } from './book-lend.controller';
import { MongooseModule } from '#nestjs/mongoose';
import { BookLendSchema } from './entities/book-lend.entity';
import { CommonService } from '../common-service/common-service.service';
import { BooksSchema } from '../books/enitiy/book.model';
#Module({
imports: [
MongooseModule.forFeature([
{ name: 'booklend', schema: BookLendSchema },
{ name: 'books', schema: BooksSchema },
]),
],
controllers: [BookLendController],
providers: [BookLendService, CommonService],
})
export class BookLendModule {}
In the service file, you need to inject the model
constructor(
#InjectModel('booklend') private readonly bookLend: Model<BookLend>,
#InjectModel('books') private readonly books: Model<Book>
) {}