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

mongoose-silo

v1.0.2

Published

A wrapper around mongose to build multi-tenant applications.

Downloads

8

Readme

mongoose-silo eases the creation of multi-tenant apps by providing a wrapper around mongoose that handles the multi-tenancy for you. It works by siloing your data accross seperate databases, one per each tenant.

Highlights

  • Singleton class Silo, that manages the database context (tenant aware)
  • Swappable tenant model; call it anything eg. Admin, Org, etc.
  • Route middleware to create tenant-aware REST endpoints using tenantify or singlify.
  • Middleware and primitives to handle the tenant context
  • CLI tool to seed fixture data across all tenants

API

  • Following excerpts demonstrate the core functionality of mongose-silo:

// Initialize `mongose-silo` with the main and tenant models
const silo = Silo.initialize('mydb', 'Admin', modelsPath)

// Switch to the database for tenant `tenantId`
silo.switch(tenantId)

// Obtains a connection to the current database 
db = () => silo.getCurrentODM()

// Create a mongo document for the current tenant
orgADashboard = db().model(“Dashboard”).create(…)
  • Use the CLI to seed fixtures into your models
# run seeders for a specific tenant
# `--tenant` here` is optional, if not provided, seeders will be run for all tenants
db:seed --seed <seed-name> --tenant <tenant-name> 

# run all seeders, either for all tenants or for a specific tenant
db:seed:all

Install


# Clone our repo
git clone https://github.com/techoutlooks/mongoose-silo \
  && DOWNLOAD_DIR="$PWD/mongoose-silo"

# Run following from your project dir
npm i --save $DOWNLOAD_DIR

# It is the responsibility of user code to export the Mongo db uri
export MONGO_URL=mongodb://localhost:27017/leeram-erp?authSource=admin

Quick start

  1. Initialize mongose-silo, ideally in your models/index.js directory.
// models/index.js

require('mongose-silo')
const silo = Silo.initialize('mydb', 'Admin', modelsPath)

module.exports = {
  silo, 
  db: () => silo.getCurrentODM(),
  tenantify: tenantify(silo),
  singlify: singlify(silo)
}
  1. Define your models as usual, but don't register them with mongose.model(name, schema). The Silo.initialize() static factory inside mongose-silo walks your modelsPath directory, compiles your schemas, and registers them with every tenant database, automagically.

const Dashboard = mongoose.model('Dashboard', Schema({
  title: String }));

// THE CHANGE: instead of registering your model yourself, 
// simply expose your schema like so:
module.exports = { name: 'Dashboard', schema: yourSchema }
  1. That's all. Now, use your models.

Remember models/schemas were pulled up automatically from the modelsPath directory and compiled, when initializing the library. You need not importing mongoose anymore.

In your controllers, replace code that looks like:

  const mongoose = require('mongoose');
  const Org = mongoose.model('Org');

with:

  const { silo, db, singlify } = require('@/models')
  const Org = db().model('Org');  // way 1
  const Org = db().Org;           // way 2

Full example:


const tenantId = 'orgA'
const { silo, db, singlify } = require('@/models/index')
silo.switch(tenantId)

await db().Dashboard.create({ 
  title: 'Org A - Weekly report' })

App routes

  • Regular route

This is meant for tenant-unaware REST calls; ie., GET with no X-Tenant-Id header, nor silo-tenant-id cookie set on the request. Below example, a trivial usecase, creates an org tenant. It uses the singlify middleware to create a route with multitenancy that:

  • inserts an org document in the main database,
  • registers models declared in the modelsPath directory per each tenant.

app.post('/org', tenantify, async (req, res) => {
  const { name, domain } = req.body

  const tenant = await silo.createTenant(domain)
  silo.switch(tenant.subdomain)

  const org = await db().Org.create({
    name, domain
  })

  res.status(201).json({
    org
  })
})
  • Tenant route

Use the tenantify middleware to switch the database context to the tenant identified in the request:


app.get('/dashboard', tenantify, async (req, res) => {
  const dashboards = await db().Dashboard.findAll()

  res.status(200).json({
    dashboards
  })
})