Comments (16)
@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.
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.
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.
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.
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.
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.
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.
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.
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.
@AliYusuf95 Can you implement your solution in the @nestjs/mongoose module?
from mongoose.
@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 mongooseBut here in same project i used NestJS MongooseModule because it doesn't have
scope
to provide REQUEST object.
Tenant ModuleI'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.
I've made a PR that contributes to this feature request, you can see at: #229
from mongoose.
Hi @marluanespiritusanto can you please provide an example reference on how to use it.
from mongoose.
@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.
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.
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)
- Subdocuments Array has not id() and remove()-method HOT 3
- Don't extend `MongooseModuleOptions` from `Record<string, any>` HOT 4
- Using getters and setters with in super class HOT 1
- Issue with RXJS dependency (0 , rxjs_1.lastValueFrom) is not a function HOT 1
- How do I integrate @casl/mongoose and how do I operate to modify the Model? HOT 1
- How do I integrate @casl/mongoose, it doesn't seem to compile through. HOT 1
- NestJS: Mongo one to many relationship doesn't work HOT 1
- cache connection HOT 1
- Support compound index in @Schema decorator HOT 1
- Unexpected ref function behaviour HOT 1
- OverwriteModelError: Cannot overwrite `X` model once compiled. HOT 2
- @Prop() schemaType on Map not working HOT 3
- findOneAndUpdate fails with multi arrayFilters in nested arrays HOT 1
- Unable to connect for non-SSL connections when specifying dbName in URI HOT 1
- Update mongoose to v8 HOT 2
- InjectModel decorator for multiple databases is broken since version 9.1.0 HOT 1
- When set connectionName to useClass, Populate Error: Schema hasn't been registered for model HOT 1
- Injecting services into MongooseModule.forFeatureAsync not triggering the middleware hooks HOT 1
- @Prop() schemaType on Map not working.
- IntersectionType and Prop decorator HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from mongoose.