Coder Social home page Coder Social logo

craftup / node-mongo-tenant Goto Github PK

View Code? Open in Web Editor NEW
72.0 6.0 25.0 1.07 MB

A multi-tenancy plugin for mongoose with tenant separation on document level. It's completely customizable, provides a neat interface for model-tenant-binding and can be disabled for running in single-tenant/on premis scenarios.

License: MIT License

JavaScript 100.00%
tenant mongo-tenant multitenancy mongoose multi-tenancy-plugin nodejs

node-mongo-tenant's Issues

Multitenant model does not override updateMany.

Hi there,

I am using .byTenant followed by updateMany in order to execute batch update. Problem is tenant model actually ignores clientId field and execute update on documents regardless tenantId field.

Add release notes

The project is currently missing release-notes.

  • add release-notes.yml file
  • publish release notes to the release notes hub
  • add badge for linking to the hosted release notes

Add support for operating on column **and** database level separated tenants.

Story

As a service operator I would like to run all my freemium tenants on a shared database with tenant separation on column level. All my premium customers data should be stored in a dedicated database, maybe even on another mongodb cluster. I want to have only one app deployment that can manage all my tenants.

Goal

The goal of this issue is to provide some kind of a per-tenant config or config resolver.

Force TenantId to be Required

Is there a way to force the tenantId to be required? I would like for the tenant id to never be null and I'm having trouble altering the schema after the plugin has ran. If I edit the mongo-tenant code, and add required: true it works. Is there something I'm missing?

Flag to disable injection on create

Add a plugin option to disable injection of tenant property when calling model.byTenant(tenant).create(),
only enables it for find, count queries

Collection-level multi-tenancy

I am a bit curious on why collection-level multi-tenancy is not recommended. I am particularly interested in micro-services scenario where each 'function' of the business is a separate microservice having a separate database. So, each database is not going to have a very large number of collections if collection-level multi-tenancy is applied. Would like to hear from you on this. Thanks

Thanks!

Beautifully designed and simple API. Great work. Awesome!

Problem with aggregation

Hello there, we are experiencing some problems using aggregate with node-mongo-tenant, your implementation of the aggregate is changing the way we need to call the aggregate function. The standart Mongoose way is:

Model.aggregate([{ $match: something }])

But the way you implemented the aggregate, we need to remove the brackets:

Model.aggregate({ $match: something })

I dont't know if this is the intended behavior, but if is not, a quick fix is possible: instead of slicing the arguments, you just need to get the pipeline passed to aggregate and unshift it to add the $match on the tenantIdKey.

  static aggregate(pipeline) {
    
    if (this.hasTenantContext) {
      pipeline.unshift({
        $match: {
          [tenantIdKey]: this[tenantIdGetter]()
        }
      })
    }

    return super.aggregate.apply(this, pipeline);
  }

How to implement node-mongo-tenant with node-restful? Newbie Question

Hi, I'm am trying to implement node_mongo_tenant with node-restful for my app, but I am struggling figuring out a way to make work.
When I define the byTenant method soon after the model, and before registering the route on node-restful, I must know the Tenant(user) by the time. As the user is going to be known only after login and the route with pre-determined tenant is already registered, I can't find a way to change the tenant constant so it will apply the right tenant to the route.
I thought on registering the route after login as solution, but it would have serious implications for the app. Is there any smarter idea? As u may see, it's a newbie question. Thanks

Problem with discriminator key

Hello, I'm trying to use mongo-tenant with mongoose discriminators. But I'm having a problem in this piece of the code:

// inherit all static properties from the mongoose base model
    for (let staticProperty of Object.getOwnPropertyNames(BaseModel)) {
      if (MongoTenantModel.hasOwnProperty(staticProperty)
      || ['arguments', 'caller'].indexOf(staticProperty) !== -1
      ) {
        continue;
      }

      MongoTenantModel[staticProperty] = BaseModel[staticProperty];
    }

    return MongoTenantModel;

This throws the following error:

TypeError: Cannot assign to read only property 'baseModelName' of function 'class MongoTenantModel extends BaseModel

The problem is that the discriminator sets a property baseModelName that has the following descriptor:

{ 
  value: 'baseModelName',
  writable: false,
  enumerable: false,
  configurable: true
}

And since is not settable, it throws an error.

Error when use `Model.aggregate`: Mongoose 5.x disallows passing a spread of operators to `Model.aggregate()`. Instead of `Model.aggregate({ $match }, { $skip })`, do `Model.aggregate([{ $match }, { $skip }])`

MongooseError: Mongoose 5.x disallows passing a spread of operators to Model.aggregate(). Instead of Model.aggregate({ $match }, { $skip }), do Model.aggregate([{ $match }, { $skip }])
at Function.aggregate (/Users/johnny/projects/work/tenant-test/node_modules/mongoose/lib/model.js:3921:11)
at Function.aggregate (/Users/johnny/projects/work/tenant-test/node_modules/mongo-tenant/index.js:295:32)
at file:///Users/johnny/projects/work/tenant-test/index.js:31:49
at Layer.handle [as handle_request] (/Users/johnny/projects/work/tenant-test/node_modules/router/lib/layer.js:102:15)
at next (/Users/johnny/projects/work/tenant-test/node_modules/router/lib/route.js:144:13)
at Route.dispatch (/Users/johnny/projects/work/tenant-test/node_modules/router/lib/route.js:109:3)
at handle (/Users/johnny/projects/work/tenant-test/node_modules/router/index.js:515:11)
at Layer.handle [as handle_request] (/Users/johnny/projects/work/tenant-test/node_modules/router/lib/layer.js:102:15)
at /Users/johnny/projects/work/tenant-test/node_modules/router/index.js:291:22
at Function.process_params (/Users/johnny/projects/work/tenant-test/node_modules/router/index.js:349:12)
at next (/Users/johnny/projects/work/tenant-test/node_modules/router/index.js:285:10)
at file:///Users/johnny/projects/work/tenant-test/index.js:22:3
at Layer.handle [as handle_request] (/Users/johnny/projects/work/tenant-test/node_modules/router/lib/layer.js:102:15)
at trim_prefix (/Users/johnny/projects/work/tenant-test/node_modules/router/index.js:330:13)
at /Users/johnny/projects/work/tenant-test/node_modules/router/index.js:294:7
at Function.process_params (/Users/johnny/projects/work/tenant-test/node_modules/router/index.js:349:12)

Support for multi tenant models

In my application there are special kind of users which may have access to different tenants, that means tenantId should be an array.

Currently it's not supported, looks like the only needed change is inside installMiddleware method which intercepts mongoose queries

Using the custom config "tenantIdKey" for create

I would like to use the tenantIdKey value automatically when I create new objects instead of hard coding it. I am using custom tenantIdKey field specified as a config value.

Instead of:

  Cup.create({...body, 'tenantId': user.id})
    .then((cup) => cup.view(true))
    .then(success(res, 201))
    .catch(next)

I think it would be nice to just specify it in a similar manner to update, delete, query where it fills in the proper key:

  Cup.byTenantId(user.id).create(body)
    .then((cup) => cup.view(true))
    .then(success(res, 201))
    .catch(next)

And it could automatically fill in the tenantId field. Not sure if this is useful or not, maybe this is a bad idea?

Pushing the tenantId filter to subdocument model for populate

Hi,
Thanks for the useful utility.
Is there a way to push the tenantId filter down into Subdocument populate.
I tried to add _conditions in pre hook of the 'find' method but the object has no clue at this stage about its parent. Find pre hook is called for each subdocument populate construct.

this.schema.pre('find', function(next) {
//add here
});
Another approach I tried, which seems to work but looks a bit cumbersome is in mongoose/lib/model.js code. Here I can fetch the parent object's tenantId and pass it to match clause of the subdocument.

Any recommendation on the right approach to implement this.

Best regards
Pav

Use Plugin Multiple Times Per Schema

Hi, I've been using this plugin for a long time now but I have an interesting use-case that I'm trying to solve without actually forking this library. Basically, we already use the plugin to add a tenantId to every mongoose model in our application, but we want to take it one step further. I wanted to add another field to the same model where I could chain the accessorMethod's and continue to narrow down the search. For example:

User

{
   name: "Aaron",
   tenantId: "A",
   tenantId2: "1"
}
{
   name: "Alrik",
   tenantId: "A",
   tenantId2: "2"
}
{
   name: "Someone",
   tenantId: "B",
   tenantId2: "2"
}

Basically as it stands right now I have to use User.byTenant("A") to get the model that I need for querying. But what I'd like to be able to do is something like User.byTenant("A").byTenant2("1") which would just return the Aaron user. I know it's not a typical use-case but just wondered if there would be an easy way to implement this. Otherwise if I end up forking it, do you have any recommendations?

support array of tenant ids to getTenant

when a user is part of multiple tenants,
to perform a mongo operation we need it to work on all tenant ids associated to the user.

currently, as a workaround, i return multiple models and execute the operation on all of them
but it will be nice to pass an array of ids

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.