NestJS Mongoose schema definition - mongodb

I have class, with nested object where I need only one field required and then all other keys are undefined and unlimited with string type, how could I write it in TypeScript?
I have tried this logic:
#Schema({ _id: false })
class Translations extends mongoose.Document {
#Prop({ required: true })
en: string;
#Prop()
[key: string]: string;
}
but mongoose complains about it

import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
import { Document } from 'mongoose';
#Schema()
export class Translation {
#Prop({required: true})
en: string;
#Prop()
[key: string]: string;
}
export const TranslationSchema = SchemaFactory.createForClass(Translation);

Related

Nestjs Mongoose nested schema is not creating default values

Here is my code that I used in my entity
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
import * as mongoose from 'mongoose';
#Schema({ _id: false })
export class Current {
#Prop({ default: '' })
operation: string;
#Prop({
default: '',
enum: [rentReportStatus.optin, rentReportStatus.optout, ''],
})
status: string;
#Prop({ default: Date.now() })
createdAt: Date;
}
const CurrentSchema = SchemaFactory.createForClass(Current);
#Schema({ collection: 'tests', timestamps: true })
export class Test extends BaseEntity {
#Prop({ type: CurrentSchema })
current: Current;
#Prop()
userId: mongoose.Schema.Types.ObjectId;
#Prop()
createdBy: mongoose.Schema.Types.ObjectId;
#Prop()
updatedBy: mongoose.Schema.Types.ObjectId;
}
export const RentReportingSchema = SchemaFactory.createForClass(RentReporting);
I tried many ways but current is not getting initialized with default values during save operation

MongoDB NestJS API dies if a #Prop is set to ObjectId

So, when i set a #Prop() to ObjectId, the api wont start, but if i set it a string it loads up just fine.
Can you help me? Thanks!
Heres the error:
Schema:
import { Prop, Schema, SchemaFactory } from "#nestjs/mongoose";
import { Document, ObjectId } from "mongoose";
export type FriendRequestDocument = FriendRequest & Document;
#Schema({collection: "friendRequests"})
export class FriendRequest {
#Prop()
author: ObjectId;
#Prop()
friend_id: ObjectId;
#Prop()
request_at: Date;
}
export const FriendRequestSchema = SchemaFactory.createForClass(FriendRequest);
edit:
I figured it out!
import { Prop, Schema, SchemaFactory } from "#nestjs/mongoose";
import mongoose, { Document, ObjectId } from "mongoose";
export type FriendRequestDocument = FriendRequest & Document;
#Schema({collection: "friendRequests"})
export class FriendRequest {
#Prop()
author: mongoose.Types.ObjectId;
#Prop()
friend_id: mongoose.Types.ObjectId;
#Prop()
request_at: Date;
}
export const FriendRequestSchema = SchemaFactory.createForClass(FriendRequest);
I dont really know why its not working.

#Prop decorator for specific nested objects in array

I have an array of objects that returns in JSON, each object looks like that:
{
"reviewId": "f1a0ec26-9aca-424f-8b05-cff6aa3d2337",
"authorName": "Some name",
"comments": [
{
"userComment": {
"text": "\tAmazing!",
"lastModified": {
"seconds": "1659685904",
},
"starRating": 5,
"reviewerLanguage": "en",
}
},
{
"developerComment": {
"text": "Thank you.",
"lastModified": {
"seconds": "1659688852",
}
}
}
]
}
I'm trying to create a Schema for this specific object, but I have some issues and I cannot understand how to create it, this is what i've done so far:
import mongoose, { Document, Mongoose } from 'mongoose';
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
export type ReviewDocument = Review & Document;
#Schema()
export class Review {
#Prop({ type: String, required: true })
reviewId: string;
#Prop({ type: String })
authorName: string;
#Prop({ type: mongoose.Schema.Types.Array })
comments: Comments[];
}
#Schema()
export class Comments {
#Prop({ type: mongoose.Schema.Types.ObjectId })
userComment: UserComment;
#Prop({ type: mongoose.Schema.Types.ObjectId })
developerComment: DeveloperComment;
}
#Schema()
export class UserComment {
#Prop({ type: String })
text: string;
#Prop({ type: String })
originalText: string;
#Prop({ type: String })
lastModified: string;
#Prop({ type: Number })
starRating: number;
#Prop({ type: String })
reviewerLanguage: string;
}
#Schema()
export class DeveloperComment {
#Prop({ type: String })
text: string;
#Prop({ type: String })
lastModified: string;
}
export const ReviewSchema = SchemaFactory.createForClass(Review);
It gives me an error:
/.../rtr-backend/src/schemas/reviews.schema.ts:21
userComment: UserComment;
^
ReferenceError: Cannot access 'UserComment' before initialization
at Object.<anonymous> (/.../rtr-backend/src/schemas/reviews.schema.ts:21:18)
at Module._compile (node:internal/modules/cjs/loader:1120:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1174:10)
at Module.load (node:internal/modules/cjs/loader:998:32)
at Function.Module._load (node:internal/modules/cjs/loader:839:12)
at Module.require (node:internal/modules/cjs/loader:1022:19)
at require (node:internal/modules/cjs/helpers:102:18)
at Object.<anonymous> (/.../rtr-backend/src/reviews/reviews.module.ts:6:1)
at Module._compile (node:internal/modules/cjs/loader:1120:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1174:10)
What is best practice?
There are a few things to notice when you define a mongoose schema:
The schema types of primitive properties (e.g. string, number) are automatically inferred, so you don't need to explicitly specify { type: String} in the decorator.
In order to preserve the nested schema validation, each object has to have its own schema or be defined using the raw schema definition.
For each nested schema please mind the default properties created by mongoose, such as timestamps, _id, __v, and so on. You could manipulate them by passing options object in the #Schema() decorator.
Here is the schema definition for your use case:
import { Prop, raw, Schema, SchemaFactory } from '#nestjs/mongoose';
import { Document, Types } from 'mongoose';
#Schema({ _id: false })
class UserComment {
#Prop({ required: true })
text: string;
#Prop(raw({ seconds: { type: Number } }))
lastModified: Record<string, number>;
#Prop({ required: true })
starRating: number;
#Prop({ required: true })
reviewerLanguage: string;
}
const UserCommentSchema = SchemaFactory.createForClass(UserComment);
#Schema({ _id: false })
class DeveloperComment {
#Prop({ required: true })
text: string;
#Prop(raw({ seconds: { type: Number } }))
lastModified: Record<string, number>;
}
const DeveloperCommentSchema = SchemaFactory.createForClass(DeveloperComment);
#Schema({ _id: false })
class Comment {
#Prop({ type: UserCommentSchema })
userComment?: UserComment;
#Prop({ type: DeveloperCommentSchema })
developerComment?: DeveloperComment;
}
const CommentSchema = SchemaFactory.createForClass(Comment);
#Schema({ timestamps: true, versionKey: false })
export class Review {
_id: Types.ObjectId;
createdAt: Date;
updatedAt: Date;
#Prop({ unique: true, required: true })
reviewId: string;
#Prop({ required: true })
authorName: string;
#Prop({ type: [CommentSchema], default: [] })
comments: Comment[];
}
export type ReviewDocument = Review & Document;
export const ReviewSchema = SchemaFactory.createForClass(Review);
PS: In this documentation page you could find plenty of use cases: https://docs.nestjs.com/techniques/mongodb
I think you need to first define the schemas in the order of their dependencies, like this:
import mongoose, { Document, Mongoose } from 'mongoose';
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
export type ReviewDocument = Review & Document;
#Schema()
export class UserComment {
#Prop({ type: String })
text: string;
#Prop({ type: String })
originalText: string;
#Prop({ type: String })
lastModified: string;
#Prop({ type: Number })
starRating: number;
#Prop({ type: String })
reviewerLanguage: string;
}
#Schema()
export class DeveloperComment {
#Prop({ type: String })
text: string;
#Prop({ type: String })
lastModified: string;
}
#Schema()
export class Comments {
#Prop({ type: mongoose.Schema.Types.ObjectId })
userComment: UserComment;
#Prop({ type: mongoose.Schema.Types.ObjectId })
developerComment: DeveloperComment;
}
#Schema()
export class Review {
#Prop({ type: String, required: true })
reviewId: string;
#Prop({ type: String })
authorName: string;
#Prop({ type: mongoose.Schema.Types.Array })
comments: Comments[];
}
export const ReviewSchema = SchemaFactory.createForClass(Review);

How to populate Nestjs mongoose schema records

I want to get then enteries from paris air quality, but the thing is that the mongoose schema is nested and I tried to make multiple schemas separated but I don't know wheter it's correct or not.
This is the schema file schemas/air-quality.schema.ts
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
import { Document } from 'mongoose';
export type AirQualityDocument = AirQuality & Document;
#Schema()
export class Pollution {
#Prop()
ts: string;
#Prop()
aqius: number;
#Prop()
mainus: string;
#Prop()
aqicn: number;
#Prop()
maincn: string;
}
#Schema()
export class Result {
#Prop({ type: Pollution })
pollution: Pollution;
}
#Schema()
export class AirQuality {
#Prop({ type: Result })
result: Result;
#Prop()
datetime: string;
}
export const AirQualitySchema = SchemaFactory.createForClass(AirQuality);
And the result I am getting from mongo is this
PS: it contains multiple entries of the same schema
[
{
"_id": "62dd1b2e744e6bf8cdbcfabd",
"result": {
"_id": "62dd1b2e744e6bf8cdbcfabe"
},
"datetime": "24/07/2022, 11:13:02",
"__v": 0
},
...
]
I don't if the mistake is with the schema or I just need to use autopopulate or something

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>
) {}