npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@wearenova/mongoose-tenant

v2.0.3

Published

A document-based multi-tenancy plugin for mongoose.

Downloads

47

Readme

A document-based multi-tenancy plugin for Mongoose v6.

npm (scoped) npm GitHub GitHub Workflow Status

Prelude

There are 3 ways of implementing multi-tenancy in mongoDB:

  • document-level (cheap and easy to administer but only secured by app logic)
  • collection-level (not recommended, due to breaking mongoDB concepts)
  • database-level (very flexible and secure but expensive)

Contents

About

Originally forked from mongo-tenant, this version of the plugin has been heavily refactored and is built with TypeScript for Mongoose v6. It is also intended to be maintained for the foreseeable future.

Mongoose Tenant is a highly configurable plugin solving multi-tenancy problems on a document level.

It creates a tenant-reference field while also taking care of unique indexes. Furthermore, a model scoped to a tenant can be created with ease. These "scoped models" limit access solely to documents of the specified tenant.

Installation

// with npm
npm install --save @wearenova/mongoose-tenant

// with yarn
$ yarn add @wearenova/mongoose-tenant

Usage

Register the plugin on the relevant mongoose schema.

import mongoose from "mongoose";
import mongooseTenant from "@wearenova/mongoose-tenant";

const MySchema = new mongoose.Schema({});
MySchema.plugin(mongooseTenant);

const MyModel = mongoose.model("MyModel", MySchema);

Retrieve the scoped model with the static byTenant method. This will return a new model subclass that has guards in place to prevent access to documents from other tenants.

const MyScopedModel = MyModel.byTenant("some-tenant-id");

new MyScopedModel().getTenant() === "some-tenant-id"; // true

// silently ignore other tenant scope
new MyScopedModel({
  tenantId: "some-other-tenant-id",
}).getTenant() === "some-tenant-id"; // true

You can check for tenant context of a model class or instance by checking the hasTenantContext property. If this is truthy you may want to retrieve the tenant, this can be done via the getTenant() method.

// When Mongoose Tenant is enabled on a schema, all scoped models
// and there instances provide the `hasTenantContext` flag
if (SomeModelClassOrInstance.hasTenantContext) {
  const tenantId = SomeModelClassOrInstance.getTenant();
  ...
}

Indexes

The Mongoose Tenant takes care of the tenant-reference field, so that you will be able to use your existing schema definitions and just plugin the Mongoose Tenant without changing a single line of the schema definition.

But under the hood the Mongoose Tenant creates an indexed field (tenant by default) and includes this in all defined unique indexes. So, by default, all unique fields (and compound indexes) are unique for a single tenant id.

You may have use-cases where you want to maintain global uniqueness. To skip the automatic unique key extension of the plugin, for a specific index, you can set the preserveUniqueKey config option to true.

const MySchema = new mongoose.Schema({
  someField: {
    unique: true,
    preserveUniqueKey: true,
  },
  anotherField: String,
  yetAnotherField: String,
});

MySchema.index(
  {
    anotherField: 1,
    yetAnotherField: 1,
  },
  {
    unique: true,
    preserveUniqueKey: true,
  },
);

Scoped Models & Populate

Once a scoped model is created it will try to keep the context for other models created via it. Whenever it detects that a subsequent models tenant configuration is compatible to its own, it will return that model scoped to the same tenant context.

const AuthorSchema = new mongoose.Schema({});
AuthorSchema.plugin(mongooseTenant);
const AuthorModel = mongoose.model("author", AuthorSchema);

const BookSchema = new mongoose.Schema({
  author: { type: mongoose.Schema.Types.ObjectId, ref: "author" },
});
BookSchema.plugin(mongooseTenant);
const BookModel = mongoose.model("book", BookSchema);

const ScopedBookModel = BookModel.byTenant("some-tenant-id");
ScopedBookModel.model("author"); // return author model scoped to "some-tenant-id"
ScopedBookModel.db.model("author"); // return author model scoped to "some-tenant-id"

Configuration

Mongoose Tenant works out of the box. All config options are optional. But, you have the ability to adjust the behaviour and api of the plugin to fit your needs.

const config = {
  /**
   * Whether the Mongoose Tenant plugin MAGIC is enabled. Default: true
   */
  enabled: false,

  /**
   * The name of the tenant id field. Default: tenant
   */
  tenantIdKey: "customer",

  /**
   * The type of the tenant id field. Default: String
   */
  tenantIdType: Number,

  /**
   * Enforce tenantId field to be set. Default: false
   */
  requireTenantId: true,
};

SomeSchema.plugin(mongooseTenant, config);