I am trying to create a database connection provider in Nestjs for MongoDB.
I inspected the user.controller.ts
and mongoDbProvider by putting breakpoints and found that the controller gets before the database connection is made. How do I make a database connection before the controllers get initialized?
Nest.js documentation says that useFactory method will run before any other module that depends on it.
src/mongo-db/mongodb.provider.ts
import { MongoClient } from "mongodb";
import { MONGODB_PROVIDER } from "../constants";
export const mongoDbProviders = [
{
provide: MONGODB_PROVIDER,
useFactory: async () => {
MongoClient.connect('mongodb://localhost:27017',
{ useUnifiedTopology: true },
(error, client) => {
return client.db('nestjs-sample');
});
}
},
];
src/mongo-db/mongo-db.module.ts
import { mongoDbProviders } from './mongo-db.providers';
@Module({
providers: [...mongoDbProviders],
exports: [...mongoDbProviders],
})
export class MongoDbModule {
}
src/constants.ts
export const MONGODB_PROVIDER = 'MONGODB_CONNECTION';
I imported MongoDbModule
into user.module.ts
src/user/user.module.ts
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { MongoDbModule } from 'src/mongo-db/mongo-db.module';
@Module({
imports: [MongoDbModule],
controllers: [UserController],
providers: [UserService]
})
export class UserModule {}
Here I injected the db
from mongoDbProvider
into UserController
constructor. But the constructor runs before db connection.
src/user/user.controller.ts
import { Controller, Post, Req, Get, Res, Inject } from '@nestjs/common';
import { Request, Response } from "express";
import { MONGODB_PROVIDER } from 'src/constants';
@Controller('users')
export class UserController {
constructor(@Inject(MONGODB_PROVIDER) private readonly db: any) {
}
@Post()
async create(@Req() request: Request, @Res() response: Response) {
this.db.collection('users').insertOne(request.body, (err, result) => {
if (err) {
response.status(500).json(err);
} else {
response.status(201);
response.send(result);
}
});
}
@Get()
get(@Req() request: Request, @Res() response: Response) {
response.status(400).json({
message: 'kidilam service'
});
}
}
Schemas are used to define Models. Models are responsible for creating and reading documents from the underlying MongoDB database. Schemas can be created with NestJS decorators, or with Mongoose itself manually.
Nest uses TypeORM because it's the most mature Object Relational Mapper (ORM) available for TypeScript. Since it's written in TypeScript, it integrates well with the Nest framework.
Nest offers a ready-to-use application architecture using controllers, providers, and modules. This enables developers and teams create applications that are simple to test and maintain. Express does not require a specific structure, which can provide flexibility for small or one-person development teams.
I found the solution. It is because the useFactory
expects a promise because it is an async
function. So I wrapped the MongoClient.connect()
inside a Promise
to resolve the database connection. Now it waits until the promise is resolved before initializing any modules that depend on it.
import { MongoClient } from "mongodb";
import { MONGODB_PROVIDER } from "../constants";
export const mongoDbProviders = [
{
provide: MONGODB_PROVIDER,
useFactory: async () => new Promise((resolve, reject) => {
MongoClient.connect('mongodb://localhost:27017',
{ useUnifiedTopology: true },
(error, client) => {
if (error) {
reject(error);
} else {
resolve(client.db('nestjs-sample'));
}
});
})
},
];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With