In this article, we are going to learn the detailed way to implement MongoDB in NestJS. Also after the setup, we will also look into performing CRUD operations with MongoDB through NestJS.
Introduction
NestJS is a framework for building scalable Node.js server-side applications. It uses the Express HTTP Server framework under the hood which is a framework based on Node.js. Nest has full TypeScript support and uses it primarily, but users can also use JavaScript. It combines the support for Object-Oriented Programming (OOP), Functional Programming (FP), and Functional Reactive Programming (FRP). NestJS gives developers the freedom to use third-party modules made for Node. Node.js. Nest provides out-of-the-box application architecture based on the Model View Controller (MVC) architecture making the written application highly testable, scalable, easily maintainable, and loosely coupled. It is heavily inspired by Angular making it easier for angular developers to get up and running NestJS faster.
MongoDB is an open-source non-relational, document-based database. It is based on storing data in an Object-based format. MongoDB runs on all platforms like Linux, Windows, and UNIX. MongoDB is one of the best No-SQL databases used for applications, ranging from web-based applications to server-side applications.
Now we are going to look at how to work with MongoDB in NestJS.
Setting up the Application – Implement MongoDB in NestJS
In this section firstly, we will initialize the nest application and add and implement the sequelize package to facilitate the MongoDB database connection.
Initializing a NestJS application
Let’s set up a Nest application by using the nest CLI.
## initializing a nest application
$ nest new nest-mongodb
## open the application with your favorite code editor
$ code nest-mongodb
Now that the nest application is initialized, we will install some dependencies that are needed for integrating MongoDB.
Adding and implementing the mongoose package
Finally, We are going to interact with MongoDB using the mongoose package which is a modern TypeScript and an ORM library that creates a connection between MongoDB and the Express-based web application frameworks. Therefore, install the mongoose package to work with and implement MongoDB in NestJS.
$ npm install --save @nestjs/mongoose mongoose
Now that the dependencies are added we need to initialize mongoose to create a connection with MongoDB. We initialize mongoose in the main module of the application, that being app.module.ts
. We add the code for connecting to the MongoDB database in the imports
key of the @Module()
decorator.
//# app.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
MongooseModule.forRoot(
'mongodb+srv://user:password@example.mongodb.net/scanskill?retryWrites=true&w=majority',
)],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
In the above code, the MongooseModule.forRoot() takes MongoDB connection URL is appended with username, password, and database name. Now let’s run the application and test our connection with the MongoDB database. These secret URLs must be kept as environment variables,to learn about interacting with environment variables look at the article How To Work With Environment Variables in Node.js.
$ npm run start:dev
If mongoose dependencies are initialized and mongoose core module dependencies are initialized, it means that the connection to the MongoDB database was a success.
Now that the connection to the database was a success. We will perform CRUD operations on MongoDB using the mongoose package.
CRUD operations
Now that we have initialized the application and created a connection with the MongoDB database, the next step is performing CRUD operations with it. We are going to interact with the user collection. For that to be possible we need to make a schema of the user collection. The reason we need to make a schema is that the mongoose package requires it for interacting with the collections present inside the MongoDB database.
Creating Schema
We are going to create a schema named user which has elements like name, email, password, createdAt, and updatedAt.
For that let’s first create a user module that houses all the user-related operations.
$ nest g module user --no-spec
Now, that the user module is created inside the user folder, we create a folder called schemas
and make a file named user.schema.ts
, that contains the user schema.
Now, let’s create the user schema
//# user.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
export type userDocument = User & Document;
@Schema({ strict: false, versionKey: false })
export class User {
@Prop()
name?: string;
@Prop({ required: true, unique: true })
email: string;
@Prop({ required: true })
password: string;
@Prop({ required: true })
createdAt: Date;
@Prop({ required: true })
updatedAt: Date;
}
export const UserSchema = SchemaFactory.createForClass(User);
We create a class that has variables that can be represented as string
, Date
, number
, and different other types. the @Schema()
decorator tells that it is a mongoose schema. the @Prop()
takes different keys like, is the value is required then the required: true
is used. If the element needs to be unique then the unique: true
is used.
If the value needs to be optional then ?: needs to be used instead of :
as seen in the case of name and email respectively. where name is optional name ?: string
is used and in the case where email is required email: string
is used.
For this schema to be usable we need to import in the user.module.ts
file, inside the imports
array of @Module()
decorator.
//# user.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { User } from './schemas/user.schema';
@Module({
imports: [MongooseModule.forFeature([{ name: User.name, schema: User }])],
})
export class UserModule {}
Now that the schema is created and imported into the user module. We will now create user controller and service.
$ nest g service user --no-spec
$ nest g controller user --no-spec
Now, the controller, service, and schema are present in the file. So, let’s move on to the main part which is performing crud operations.
Create operation
We are going to create a method called insertOne()
inside user service and controller, which creates users.
//# user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, userDocument } from './schemas/user.schema';
@Injectable()
export class UserService {
constructor(
@InjectModel(User.name) private readonly model: Model<userDocument>,
) {}
async insertOne(data): Promise<User> {
return await new this.model({
...data,
createdAt: new Date(),
updatedAt: new Date(),
}).save();
}
}
//# user.controller.ts
import { Body, Controller, Post} from '@nestjs/common';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post()
async insertOne(@Body() body) {
return await this.userService.insertOne(body);
}
}
Now, let’s create an HTTP POST request at /user
route
We see that the data has been successfully present on the database.
Read operation
For the read let’s create findAll()
method which finds all the data present inside the user collection.
//# user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, userDocument } from './schemas/user.schema';
@Injectable()
export class UserService {
constructor(
@InjectModel(User.name) private readonly model: Model<userDocument>,
) {}
async findAll(): Promise<User[]> {
return await this.model.find().exec();
}
}
//# user.controller.ts
import { Body, Controller, Get } from '@nestjs/common';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get()
async findAll() {
return await this.userService.findAll();
}
}
Now let’s create an HTTP GET request on the /user
route
We see that all the data present inside the user collection were in response.
Update operation
For update let’s create updateOne()
method inside the user controller and service.
//# user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, userDocument } from './schemas/user.schema';
@Injectable()
export class UserService {
constructor(
@InjectModel(User.name) private readonly model: Model<userDocument>,
) {}
async updateOne(id: string, data): Promise<User> {
const updatedAt = new Date();
const oldPayload = await this.model.findByIdAndUpdate(id, {
...data,
updatedAt,
});
const result: any = {
_id: oldPayload._id,
email: data.email || oldPayload.email,
password: data.password || oldPayload.password,
createdAt: oldPayload.createdAt,
updatedAt: updatedAt,
};
return result;
}
}
//# user.controller.ts
import { Body, Controller, Param, Put } from '@nestjs/common';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
@Put('/:id')
async updateOne(@Param('id') id: string, @Body() body) {
return await this.userService.updateOne(id, body);
}
}
Now, let’s send an HTTP PUT request with the user id of /user/:id
.
Before update
After update
So, we can see that the data that was sent has been updated in the user collection.
Delete operation
Now let’s create deleteOne()
method which deletes the user with matched id.
//# user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, userDocument } from './schemas/user.schema';
@Injectable()
export class UserService {
constructor(
@InjectModel(User.name) private readonly model: Model<userDocument>,
) {}
async deleteOne(id: string): Promise<User> {
return await this.model.findByIdAndDelete(id);
}
}
//# user.controller.ts
import { Controller, Delete, Param } from '@nestjs/common';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
@Delete('/:id')
async deleteOne(@Param('id') id: string) {
return await this.userService.deleteOne(id);
}
}
Now, let’s send an HTTP DELETE request at /user/:id
route.
We can see that the single user present in the user collection has been deleted.
So, this concludes performing CRUD operation in MongoDB with NestJS.
Conclusion
In this article saw and learned how to work and implement MongoDB with NestJs along with performing CRUD operations on it. For learning backend development along with NestJs visit JavaScript Backend Development Course For Beginners.