Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change a Database connection dynamically with Request Scope Providers in Nestjs?

Working on a project with Nestjs 6.x, Mongoose, Mongo, etc... Regarding to the Back End, in my use case, I must change the connection of one of my databases depending of some conditions/parameters coming from some requests.

Basically, I have this

mongoose.createConnection('mongodb://127.0.0.1/whatever-a', { useNewUrlParser: true })

and I want to change to, for example

mongoose.createConnection('mongodb://127.0.0.1/whatever-b', { useNewUrlParser: true })

Therefore, I have in Nestjs the first provider

export const databaseProviders = [
  {
    provide: 'DbConnectionToken',
    useFactory: async (): Promise<typeof mongoose> =>
    await mongoose.createConnection('mongodb://127.0.0.1/whatever', { useNewUrlParser: true })
  }

I was researching for a while and I found out that in release Nestjs 6.x there are provider requests allowing me to modify dynamically Per-request the injection of some providers.

Anyway, I don't know how to achieve my change neither if it is going to be working in case I'd achieve that

Can anyone help or guide me? Many thanks in advance.

like image 626
ackuser Avatar asked Mar 04 '23 04:03

ackuser


1 Answers

You can do the following using Nest's built-in Mongoose package:

/*************************
* mognoose.service.ts
*************************/
import { Inject, Injectable, Scope } from '@nestjs/common';
import { MongooseOptionsFactory, MongooseModuleOptions } from '@nestjs/mongoose';
import { REQUEST } from '@nestjs/core';
import { Request } from '@nestjs/common';

@Injectable({ scope: Scope.REQUEST })
export class MongooseConfigService implements MongooseOptionsFactory {
    constructor(
        @Inject(REQUEST) private readonly request: Request,) {
    }

    createMongooseOptions(): MongooseModuleOptions {
        return {
            uri: request.params.uri, // Change this to whatever you want; you have full access to the request object.
        };
    }
}

/*************************
* mongoose.module.ts
*************************/
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { MongooseConfigService } from 'mognoose.service';

@Module({
    imports: [
        MongooseModule.forRootAsync({
            useClass: MongooseConfigService,
        }),
    ]
})
export class DbModule {}

Then, you can attach whatever you want to the request and change the database per request; hence the use of the Scope.REQUEST. You can read more about Injection Scopes on their docs.


Edit: If you run into issues with PassportJS (or any other package) or the request is empty, it seems to be an error that relates to PassportJS (or the other package) not supporting request scopes; you may read more about the issue on GitHub regarding PassportJS.

like image 196
yaserso Avatar answered Mar 06 '23 23:03

yaserso