Exploring a NestJS Application with MongoDB Using Mongoose: A Beginner’s Guide (P1)

kelvinBz
5 min readJun 21, 2024

--

This guide provides a simple overview of setting up a NestJS application with MongoDB using the Mongoose module. It includes creating modules, services, schemas, and integrating Mongoose for database operations, illustrated with diagrams for clarity. If you prefer the coding version, you can explore the code here: https://github.com/kelvin-bz/nestjs-mongoose

The application will be very simple to create and list the users

Nestjs — MongoDB flow of creating and listing users

Overview

Code Structure

├── app.controller.ts
├── app.module.ts
├── app.service.ts
├── config
│ └── database.config.ts
├── main.ts
└── users
├── dto
│ └── create-user.dto.ts
├── schemas
│ └── user.schema.ts
├── user.module.ts
├── users.controller.ts
└── users.service.ts
Code Structure of a NestJS Application with MongoDB Integration

Config Directory

  • config/database.config.ts: Configuration file for database settings, including MongoDB connection details.

Users Directory

This directory contains all the components related to the user functionality, including DTOs, schemas, modules, controllers, and services.

  • dto/create-user.dto.ts: Defines the data transfer object (DTO) for creating a user. This specifies the shape of the data sent to the application.
  • schemas/user.schema.ts: Defines the Mongoose schema for the User model. This schema maps to a MongoDB collection and defines the structure of the documents within that collection.
  • user.module.ts: The module that imports MongooseModule to define and connect the User schema. This module organizes the users' related components and integrates Mongoose for database operations
  • users.controller.ts: Handles incoming HTTP requests related to user operations, such as creating and retrieving users. It uses UsersService to perform these operations.
  • users.service.ts: Contains the business logic for user operations. It interacts with the UserModel to perform database operations such as creating and retrieving users.

AppModule with Dynamic Mongoose Module Configuration

// src/app.module.ts
// .. import
@Module({
imports: [
ConfigModule.forRoot({
load: [databaseConfig],
envFilePath: '.env',
isGlobal: true,
}),
MongooseModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => {
return {
uri: configService.get(CONFIG_DATABASE).users.uri,
};
},
inject: [ConfigService],
}),
UsersModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

// src/config/database.config.ts
import { registerAs } from '@nestjs/config';

export const CONFIG_DATABASE = 'database';

export default registerAs(CONFIG_DATABASE, () => ({
users: {
uri: process.env.DATABASE_URL,
},
}));

The AppModule is the root module of your NestJS application. It imports and configures several modules:

  • ConfigModule: Loads configuration from .env and is globally available.
  • MongooseModule: Asynchronously sets up the MongoDB connection using configuration from ConfigModule. You place this in your root AppModule, ensuring the connection is established once and is available throughout the entire app. Using forRootAsync, you can dynamically configure this connection at runtime, pulling in environment variables or other configuration settings as needed.
  • UsersModule: Manages user-related functionality

With Mongoose, the dynamic module setup MongooseModule.forRootAsync enables the database connection to be configured based on environment variables or external inputs. This approach provides enhanced scalability and adaptability, ensuring that the application can handle various deployment scenarios. It allows the module to be customized dynamically, improving maintainability and flexibility.

A dynamic module in NestJS allows for asynchronous configuration and dependency injection at runtime, making it highly flexible and adaptable. It enables the module to be configured dynamically based on runtime conditions or external inputs, such as environment variables or configuration files. This is particularly useful for setting up complex dependencies like database connections. Dynamic modules enhance scalability and maintainability by allowing for more sophisticated initialization logic. https://docs.nestjs.com/fundamentals/dynamic-modules

Dynamic Module and Static Module

User Module

The Users module is where all the user-related functionality is encapsulated. It includes the controller, service, and schema definitions.

// import ...

@Module({
imports: [
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
],
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}
User Module

MongooseModule.forFeature

The MongooseModule.forFeature is where you set up the specifics for each feature module, like UsersModule. This is where you register your Mongoose schemas and create models. You use it within each feature module to define and connect the necessary models, ensuring each module has access to the database structures it needs to function.

User Controller — User Service — User Schema

This diagram illustrates the interactions between the User Controller, User Service, User Schema, and Create User DTO in a NestJS application. The User Controller uses the Create User DTO for data validation and calls service methods in the User Service. The User Service receives validated data from the Create User DTO and interacts with the User Schema for database operations.
Interactions between the User Controller, User Service, User Schema, and Create User DTO in a NestJS application

Users controller handles incoming requests related to users, such as creating, retrieving, and deleting user records.

// src/users/dto/create-user.dto.ts
export class CreateUserDto {
readonly name: string;
readonly age: number;
}
// src/users/users.controller.ts
// import ...

@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}

@Post()
async create(@Body() createUserDto: CreateUserDto) {
await this.usersService.create(createUserDto);
}

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

The Users service handles the business logic related to users, including creating and retrieving user records from the MongoDB database.

// src/users/users.service.ts
// import ...

@Injectable()
export class UsersService {
constructor(@InjectModel(User.name) private userModel: Model<User>) {}

async create(createUserDto: CreateUserDto): Promise<User> {
const createdUser = new this.userModel(createUserDto);
return createdUser.save();
}

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

The User schema defines the structure of the user documents stored in the MongoDB database.

User Schema
// src/users/schemas/user.schema.ts
// import ...

export type UserDocument = HydratedDocument<User>;

@Schema()
export class User {
@Prop()
name: string;

@Prop()
age: number;
}

export const UserSchema = SchemaFactory.createForClass(User);

Testing the User Module

Create User

To create a new user, send a POST request to the endpoint below with the user details in the request body.

POST http://localhost:3000/users
Content-Type: application/json

{
"name": "John Doe",
"age": 30
}

Get All Users

To retrieve all users, send a GET request to the endpoint below.

GET http://localhost:3000/users

Conclusion

This guide illustrates how to set up a NestJS application with Mongoose to manage user data efficiently. By using MongooseModule.forRoot for connecting to MongoDB and MongooseModule.forFeature for registering schemas, you create a well-structured and maintainable system. The clear relationships between the User Controller, Service, Schema, and DTO ensure seamless data handling, providing a solid foundation for your application's user management needs.

Next : https://kelvinbz.medium.com/exploring-a-nestjs-application-with-mongodb-using-mongoose-a-beginners-guide-multiple-database-dcb55dff1c90

Read more articles about NestJS : https://kelvinbz.medium.com/list/nestjs-eafb7de3e562

Read more articles about AWS: https://kelvinbz.medium.com/list/aws-32c5d9525c7d

--

--

kelvinBz
kelvinBz

Written by kelvinBz

Software Engineer | MongoDB, AWS, Azure Certified Developer

No responses yet