DEV Community

Tarun Singh
Tarun Singh

Posted on

11 1

Create Custom Database Module in NestJS

Introduction

When talking about connecting databases in NestJS, we have TypeORMModule for MySQL and MongooseModule for MongoDB available. There might be a scenario where we are required to connect to a database with our own/custom database module. This could be an example when we want to connect to MongoDB native driver without using mongoose ORM.

Prerequisite

This is for someone who is beginner in NestJS and has the understanding of TypeScript. Optionally, has used TypeORM or Mongoose module in NestJS projects.

Custom Providers in NestJS

If you have been working in NestJS for a while (obviously if you are reading this blog), you may have used providers which is created using dependency injection. we can create our own custom providers concerning the requirements of the project. One such custom provider and its module we are going to create here. Read more about custom providers here

Modules in NestJS

Modules are nothing but segregation of an application into smaller parts that are individually responsible for certain roles or features of the application. In NestJS, we have at least one module, which is at the root level. We are going to create a custom database module for MongoDB.

Implementation and Explanation

Create new nest project as,
$ nest new custom-db-project

Now generate the custom database module as,
$ nest generate module database

Now create provider for database module as,
$ touch src/database/database.provider.ts

We will also install MongoDB driver,
$ npm install --save mongodb
...
Let's Code,

  • First we will create the provider for mongodb driver as,
import * as mongodb from 'mongodb';

export const databaseProviders = [
    {
        provide: 'DATABASE_CONNECTION',
        useFactory: async (): Promise<mongodb.Db> => {
            try {
                const client = await mongodb.MongoClient.connect(
                    'mongodb://localhost',
                    {
                        useUnifiedTopology: true,
                    },
                )
                const db = client.db('test');

                return db;
            } catch (error) {
                throw error;
            }
        }
    }
]
Enter fullscreen mode Exit fullscreen mode
  • We will define the provider as variable in which provider name is 'DATABASE_CONNECTION', this will be used when we are injecting database provider in other modules so that we can use it.
  • In useFactory, we are initialising the actual mongodb driver and return the 'db' that is the exact variable to used in other modules.
  • We are first establishing the connection using 'connect' function and then linking to 'test' database and finally returning 'db'. ...
  • Now we will come back to database module which we generated and has the basic implementation of the Module annotation of NestJS.
import { Module } from '@nestjs/common';

@Module({})
export class DatabaseModule {}

Enter fullscreen mode Exit fullscreen mode
  • We will modify this structure as,
import { Module } from '@nestjs/common';
import { databaseProviders } from './database.provider';

@Module({
    providers: [...databaseProviders],
    exports: [...databaseProviders]
})
export class DatabaseModule { }

Enter fullscreen mode Exit fullscreen mode
  • Here we specified that module has to consider the objects in 'databaseProviders' array as the provider, so hence it can be recognised the project structure.
  • Also, we need to export these providers so that they can be used in other modules. ...
  • Now we will create another module just to demonstrate the use of Database Module.

  • Generate todo Module as,
    $ nest generate module todo

  • Generate todo service so that we can interact with DatabaseModule,this also generate 'todo.service.spec.ts' file which is a test file and we can ignore it as we are not discussing it here.
    $ nest generate service todo

  • Now we will add the DatabaseModule in TodoModule,

import { Module } from '@nestjs/common';
import { DatabaseModule } from 'src/database/database.module';
import { TodoService } from './todo.service';

@Module({
    imports: [DatabaseModule],
    providers: [TodoService]
})
export class TodoModule { }

Enter fullscreen mode Exit fullscreen mode
  • In imports we have defined that DatabaseModule this will allow the todo module structure to make the use of database providers. ...
  • Now we will inject Database provider in todo service provider, hence the service will have the access to database functions.
import { Inject, Injectable } from '@nestjs/common';
import * as mongodb from 'mongodb';

@Injectable()
export class TodoService {
    constructor(@Inject('DATABASE_CONNECTION') private db: mongodb.Db) { }

    async getAllTodos(): Promise<any[]> {
        return await this.db.collection('todos').find({}).toArray();
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Remember that we had named the database provider name as 'DATABASE_CONNECTION', you can see it is being used here in constructor to import/inject the 'db'.
  • And in 'getAllTodos' function we can see how 'db' is used to find data in the given collection.

Finally we implemented the custom database module for MongoDB in NestJS, also this implementation does not force us to make the use of schemas unlike mongoose, which can be a requirement in some projects.

Hot sauce if you're wrong - web dev trivia for staff engineers

Hot sauce if you're wrong ยท web dev trivia for staff engineers (Chris vs Jeremy, Leet Heat S1.E4)

  • Shipping Fast: Test your knowledge of deployment strategies and techniques
  • Authentication: Prove you know your OAuth from your JWT
  • CSS: Demonstrate your styling expertise under pressure
  • Acronyms: Decode the alphabet soup of web development
  • Accessibility: Show your commitment to building for everyone

Contestants must answer rapid-fire questions across the full stack of modern web development. Get it right, earn points. Get it wrong? The spice level goes up!

Watch Video ๐ŸŒถ๏ธ๐Ÿ”ฅ

Top comments (2)

Collapse
 
devkaahl profile image
Muhammad Khalil โ€ข

Great article yo...

How do I dynamically pass the database name to the provider, 'DATABASE_PROVIDER'?

Collapse
 
codecoffeesleep profile image
Mohammad hasan daneshvar โ€ข

It's really helpful, thank you

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

๐Ÿ‘‹ Kindness is contagious

Please leave a โค๏ธ or a friendly comment on this post if you found it helpful!

Okay