How to Integrate MongoDB with NestJS

Updated: December 31, 2023 By: Guest Contributor Post a comment

Overview

NestJS, a powerful Node.js framework, can be effectively integrated with MongoDB, a popular NoSQL database. This tutorial guides you through the process step by step.

By the end of this tutorial, you will know how to set up a NestJS project configured to connect with a MongoDB database, use Mongoose for schema models, and perform CRUD operations. We’ll take a practical approach, walking through essential steps and providing code snippets to illustrate the integration.

Prerequisites:

  • Node.js installed
  • NPM or Yarn as a package manager
  • Basic knowledge of TypeScript and NestJS
  • MongoDB account and database set up

Setting up a NestJS Project

npm i -g @nestjs/cli
nestjs new project-name

This command installs the NestJS CLI globally and scaffolds a new project.

Installing Mongoose and NestJS/Mongoose

npm install @nestjs/mongoose mongoose

These packages provide the necessary tools to integrate MongoDB via Mongoose in your application.

Configuring the MongoDB Connection

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';

@Module({
  imports: [
    MongooseModule.forRoot('mongodb+srv://your-db-uri', {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    }),
  ],
})
export class AppModule {}

Replace ‘your-db-uri’ with your actual MongoDB URI. The options `useNewUrlParser` and `useUnifiedTopology` are included for compatibility.

Defining a Schema Model

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

@Schema()
export class Cat extends Document {
  @Prop({ required: true })
  name: string;

  @Prop()
  age: number;

  @Prop()
  breed: string;
}

export const CatSchema = SchemaFactory.createForClass(Cat);

This code defines a simple `Cat` schema with the `@Prop` decorator to denote the properties.

Creating a Module

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { Cat, CatSchema } from './schemas/cat.schema';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: Cat.name, schema: CatSchema }]),
  ],
})
export class CatsModule {}

The `CatsModule` incorporates the `Cat` schema, making it available within this specific module.

Service Layer

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Cat } from './schemas/cat.schema';

@Injectable()
export class CatsService {
  constructor(@InjectModel(Cat.name) private catModel: Model) {}

  async create(createCatDto: { name: string; age: number; breed: string }): Promise {
    const createdCat = new this.catModel(createCatDto);
    return createdCat.save();
  }

  async findAll(): Promise<Cat[]> {
    return this.catModel.find().exec();
  }
}

The `CatsService` utilizes the model to provide create and find operations for the cat entities.

Controller Layer

import { Controller, Get, Post, Body } from '@nestjs/common';
import { CatsService } from './cats.service';
import { Cat } from './schemas/cat.schema';

@Controller('cats')
export class CatsController {
  constructor(private catsService: CatsService) {}

  @Post()
  async create(@Body() createCatDto: { name: string; age: number; breed: string }): Promise {
    return this.catsService.create(createCatDto);
  }

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }
}

The `CatsController` exposes endpoints to create a new cat and fetch all cats, relying on the service layer for business logic.

CRUD in Action

To see this in action, use your API testing tool to hit the endpoints such as `POST /cats` to create and `GET /cats` to retrieve cat entries.

Advanced: Data Transfer Objects (DTOs)

Now let’s cover some advanced topics including using DTOs for data transfer, implementing middleware for validation, using async hooks with Mongoose, and incorporating transactions.

import { IsString, IsNumber } from 'class-validator';

export class CreateCatDto {
  @IsString()
  readonly name: string;

  @IsNumber()
  readonly age: number;

  @IsString()
  readonly breed: string;
}

DTOs like `CreateCatDto` help ensure that data conforms to the specified format and types.

Conclusion

Integration of MongoDB with NestJS empowers developers to build scalable and maintainable applications. Using Mongoose within NestJS combines the robustness of TypeScript with the flexibility of MongoDB. Take the concepts here as a springboard to create complex, production-grade apps.