GithubHelp home page GithubHelp logo

Request scoped connections about mongoose HOT 16 CLOSED

nestjs avatar nestjs commented on April 20, 2024 5
Request scoped connections

from mongoose.

Comments (16)

aneudysamparo avatar aneudysamparo commented on April 20, 2024 2

@DenisPalchuk I think this may depends on the case!
For me I'd like to use a different DB depending on the request (subdomain). Just trying to make a multi-tenancy app based on domain/subdomain names.

currently i could this make it work but using MongooseModule and mongoose lib per-sé, which I think is a big force!

Check this!
Database Provider - set database dynamically based on subdomain using just mongoose

But here in same project i used NestJS MongooseModule because it doesn't have scope to provide REQUEST object.
Tenant Module

I'd like to use just NestJS MongooseModule with custom provider (scope)

What do you think?

from mongoose.

kamilmysliwiec avatar kamilmysliwiec commented on April 20, 2024 2

It looks great at first sight :) @adriano-di-giovanni Think about writing an article about it, I think many people would be interested!

from mongoose.

AliYusuf95 avatar AliYusuf95 commented on April 20, 2024 1

I did a simple implementation for nest-mongodb, please check it out

The main changes are in mongo-core.module.ts where I store the connections in a map and used them if available instead of creating a new connection every time.

I test it and it works with Request scoped MongooseOptionsFactory for the DB Module

from mongoose.

adriano-di-giovanni avatar adriano-di-giovanni commented on April 20, 2024 1

I've just published a gist of a multi-tenant mongoose module for nest.

I'm relatively new to Nest and I'd like to have your feedback.

@kamilmysliwiec is that something valid?

from mongoose.

sandeepsuvit avatar sandeepsuvit commented on April 20, 2024 1

I have put together a library based on @adriano-di-giovanni gist and made some modifications to it. Here is the repository nest-tenancy. Would love to hear your comments on it @kamilmysliwiec
And thanks @adriano-di-giovanni for your gist, which really helped :)

from mongoose.

dryize avatar dryize commented on April 20, 2024 1

I spent the whole day trying to figure out the best way to implement this. To try out I took the concept from @adriano-di-giovanni and lib from @sandeepsuvit and implemented a fully working solution.
I was able to solve the issues with global auth guards, passport, graphql. You can check the source code from below git repo.
https://github.com/databoxtech/nestjs-multi_tenant-multiple-database

I've added two global guards, one for jwt auth and another to ensure tenancy. Both are applied at global level and ignore the /auth/login endpoint. For any other endpoint TenancyGuard will make sure tenancy present in header and the jwt token are equal. This takes away the vulnerability where you can access other tenants once you are logged into one by altering headers.

Many thanks to all the contributors.
Im now evaluating solution from this stack, https://stackoverflow.com/questions/56085705/how-can-i-setup-multitenant-in-nestjs

from mongoose.

kamilmysliwiec avatar kamilmysliwiec commented on April 20, 2024

Great idea. We'll likely implement this at some point.

For those who are looking for a workaround, you can always create your own MongooseModule like described here: https://docs.nestjs.com/recipes/mongodb

from mongoose.

DenisPalchuk avatar DenisPalchuk commented on April 20, 2024

Is it a good idea to provide new connection per request? Let's check docs:
http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html#mongoclient-connection-pooling

As you can see mongo driver created connection pool under the hood after init app and provided db object for sharing it across app. Creating connection pool per request is a bad idea.

As a workaround we can use mongo transactions (which work only with 4.x version and only with replica set) + CLS.

from mongoose.

AliYusuf95 avatar AliYusuf95 commented on April 20, 2024

I need this feature too.

I think the Provider should be smart enough to eather to use an existing connection or generate a new connection to the requested database if the connection is not initiated before.

from mongoose.

marluanespiritusanto avatar marluanespiritusanto commented on April 20, 2024

@AliYusuf95 Can you implement your solution in the @nestjs/mongoose module?

from mongoose.

sandeepsuvit avatar sandeepsuvit commented on April 20, 2024

@DenisPalchuk I think this may depends on the case!
For me I'd like to use a different DB depending on the request (subdomain). Just trying to make a multi-tenancy app based on domain/subdomain names.

currently i could this make it work but using MongooseModule and mongoose lib per-sé, which I think is a big force!

Check this!
Database Provider - set database dynamically based on subdomain using just mongoose

But here in same project i used NestJS MongooseModule because it doesn't have scope to provide REQUEST object.
Tenant Module

I'd like to use just NestJS MongooseModule with custom provider (scope)

What do you think?

Small update to @aneudysamparo solution which is similar to what i followed, but modified the code for returning any existing connection instead of creating a new one for every concurrent requests.

import * as mongoose from 'mongoose';
import { Connection } from 'mongoose';
import { REQUEST } from '@nestjs/core';
import { Scope, NotFoundException } from '@nestjs/common';
import { TenantsService } from '../tenants/tenant.service';


export const databaseProviders = [
    {
        provide: 'DATABASE_CONNECTION',
        scope: Scope.REQUEST,
        useFactory: async (req, tenants: TenantsService): Promise<typeof mongoose> => {
            if (req.subdomains[0] && req.subdomains[0] !== undefined && req.subdomains[0] !== 'undefined') {
                const tenantDB: string = req.subdomains[0];
                let foundTenant = await tenants.findOne({ subdomain: tenantDB });
                if (!foundTenant) {
                    throw new NotFoundException('AppName does not exits');
                }
                // Check if is actived
                console.log(foundTenant);

                // Get the underlying mongoose connections
                const connections: Connection[] = mongoose.connections;

                // Find existing connection
                const foundConn = connections.find((con: Connection) => {
                    return con.name === tenantDB;
                });

                // Return the same connection if it exist
                if (foundConn && foundConn.readyState === 1) {
                    return foundConn;
                }

                return mongoose.createConnection(`mongodb://localhost/${foundTenant.tenantdb}`, { useNewUrlParser: true });
            } else {
                return mongoose.createConnection(`mongodb://localhost/TodoAppDB`, { useNewUrlParser: true });
            }
        },
        inject: [REQUEST, TenantsService]
    }
];

from mongoose.

marluanespiritusanto avatar marluanespiritusanto commented on April 20, 2024

I've made a PR that contributes to this feature request, you can see at: #229

from mongoose.

sandeepsuvit avatar sandeepsuvit commented on April 20, 2024

Hi @marluanespiritusanto can you please provide an example reference on how to use it.

from mongoose.

sandeepsuvit avatar sandeepsuvit commented on April 20, 2024

@adriano-di-giovanni Thats a nice implementation. Would love to see an article about it like @kamilmysliwiec said, as many of us are waiting for an approach on Multi-tenancy using Nestjs.

I have tried multiple approaches on this using REQUEST scope (to extract the TENANT_ID), but the issue i faced while using REQUEST scope is that the passport module gets blocked and wont work since they are global scoped.

from mongoose.

AliYusuf95 avatar AliYusuf95 commented on April 20, 2024

I had tried to implement this in several ways, but I don't fee it the right way to do it.
What I want to achieve the following:

  • The module has a default connection.
  • Fallback to the default connection if the request doesn't have a tenant connection.
  • The connection should be reused whenever it's possible.
  • Named connection feature (to force creation a different connection).
  • Tenants connection configurations can be loaded from the base connection.
  • Ability to inject the right connection seamlessly.
  • Avoid Scope.REQUEST as much as possible (for efficiency).

The last two points which make things hard, they are critical to me since I don't want to recreate the services and all other components for each request -it should be efficient- and I want use the right connection easily.

Since the request is only available in the controller and the previous stages, without having Scope.REQUEST or passing it as a parameter, the connections can be created in an interceptor for example -so we can use req.user from passport to get the tenant- and store it in a connection store, then this store can be used in the other services.

But the usage of the connection will not we seamlessly like what this library offers, where the mongoose model is injected directly in the service instead of the connections store. Also, we have to pass the (request/user/tenant ref) to the service if we want to avoid the Scope.REQUEST.

from mongoose.

kamilmysliwiec avatar kamilmysliwiec commented on April 20, 2024

Thanks for your suggestion!

This has been discussed in the past and we decided to not implement it in the foreseeable future.

If you think your request could live outside Nest's scope, we'd encourage you to collaborate with the community on publishing it as an open source package.

from mongoose.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.