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-sublease

v0.5.0

Published

A library to help make database-level multitenancy in mongoose easy

Downloads

943

Readme

mongoose-sublease

NPM version Dependency Status Dev Dependency Status Code Climate Build Status Coverage Status

Makes is easy to do database-level multitenancy with mongoose. Even easier with express.

Installation

npm install --save mongoose-sublease

This module has a peer dependency of mongoose of >= version 4. It depends on the .useDb() functionality, so it would probably work on >= 3.8, but this module is only tested with version 4.

Also, this module requires a user that has access to multiple databases, which is kind of a scary thought. It is definitely not recommended that you just use an admin user. I haven't verified this, but this is the kind of user you want. You might be able to narrow this down even more. If you are able to, let me know and I'll update this doc to represent the least priviledges you need to work correctly:

$ mongo
> use admin
> db.addUser({ user: "foo", pwd: "bar", roles: [ "userAdminAnyDatabase", "readWriteAnyDatabase" ]})

Then when you authenticate, your mongo uri should look something like this:

mongodb://foo:bar@localhost/admin?authSource=admin

The important part there is the authSource=admin, which tells mongo which database to use when authenticating. Your multi-database user should be added to the admin database.

Usage

With Express

'use strict'

const express = require('express')
const subleaseMiddleware = require('mongoose-sublease/express')
const mongoose = require('mongoose')

mongoose.Promise = Promise
mongoose.connect('mongodb://localhost')

const app = express()
const userSchema({
  username: String,
  email: String,
  password: String,
})

app.use(subleaseMiddleware(mongoose.connection, {
  User: userSchema,
}))
app.get('/users', (req, res, next) => {
  req.model('User')
    .find()
    .then((users) => res.json(users))
    .catch(next)
})

app.listen(8000)

Raw Usage

'use strict'

const sublease = require('mongoose-sublease')
const mongoose = require('mongoose')

mongoose.Promise = Promise
mongoose.connect('mongodb://localhost')

const userSchema({
  username: String,
  email: String,
  password: String,
})

const getTenant = sublease(mongoose.connection, {
  User: userSchema,
})

const tenant1 = getTenant('tenant1') // 'tenant1' is the database name
const tenant2 = getTenant('tenant2') // 'tenant2' is the database name

tenant1.model('User')
  .create({
    username: 'foo',
    email: '[email protected]'
    password: 'correct horse battery stable',
  })
  .then(() => {
    return tenant2.find()
  })
  .then((tenant2Users) => {
    console.log(tenant2Users) // empty []
  })

API

sublease(rootConnection, models)

Returns a function that you call with a database name, which returns a new mongoose connection (which shares the same connection pool) and has all of your monogoose models.

  • rootConnection Mongoose Connection - The root connection to base other connections off of. If you're using the main mongoose connection, use mongoose.connection.

  • models Object{string:mongoose.Schema} - And Object map who's keys are the model name and values are the corresponding schemas.

    const userSchema = new mongoose.Schema({
      name: String
    })
    app.use(
      mongooseModel(mongoose.connection, {
        User: userSchema
      })
    )

subleaseMiddleware(rootConnection, models, options)

Returns a middleware that applies the connection info to the request. The rootConnection and models arguments are the same as above.

  • options.connectionKey String - The key to use when attaching the connection to the request object. Default: mongooseConnection. e.g. req.mongooseConnection.

  • options.tenantKey String - The key to use when attaching the name of the tenant. Default tenant. e.g. req.tenantKey.

  • options.modelKey String - The key to use when attaching the model method that retrieves the models by name. This is essentially a shortcut for connection.model(modelName). Default model. e.g. req.model(modelName).

  • options.getDbName Function - The function to call to get the database name to use. Defaults to just getting the database name of the root connection. This function gets passed the request object and the root connection (respectively) and must return a string as it will be used as a key to keep track of tenants. Default: (req, connection) => connection.name

Notes

Only express middleware is provided, but with enough interest, I could be convinced to support middleware for other popular http server frameworks. Or just write your own! It's not too hard. In fact, this whole module isn't too difficult to reproduce. In fact, maybe this whole this is just over-engineered. It's open source, feel free to take it, and modify it, use it, take credit for it, whatever.

This whole module came about because of a folder structure that I tend to follow for my node projects. I have a lib/ folder, which is used for non-business specific logic, things which could become generic enough as a standalone node module. It's not super magical, but it definitely reduces boilerplate.