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

v1.0.0

Published

Object inheritance for mongoose connections, models and documents

Downloads

5

Readme

mongoose-context

Attach custom context data to mongoose that is inherited by models, document instances and sub-documents.

Installation

$ npm install mongoose-context

Introduction

When performing multiple asynchronous operations at the same time with Mongoose it sure would be nice if you could attach some custom data to a model and use it in callbacks to connect the right results back to the right operation. Using ExpressJS for instance, it would be very helpful if you could attach the request and response objects to a mongoose model and have these objects available in any callback invoked for operations using that particular model. That way, multiple incoming requests could easily be processed at the same time and the results linked back to the right response. Unfortunately, Mongoose uses singletons for models which makes this whole idea a bit tricky. Mongoose-context makes this process much easier by generating a mongoose instance with a custom object attached to it. Any models generated by this mongoose instance will inherit this same object and any document instances produced by any of these models will have access to this object as well. Even sub-documents will inherit this data from the main document instance. The plugin supports promises, queries, QueryStreams and middleware and is compatible with Mongoose versions 3.8 and 4.x.

The context inheritance model is best illustrated in a tree structure as follows:

mongoose --> context1
  model_A
    document_A1
      subdoc_A1[]
    document_A2
      subdoc_A2[]
  model_B
    document_B1
      subdoc_B1[]
    document_B2
      subdoc_B2[]

Object context1 is attached to a mongoose instance and available to all child models, documents and sub-documents generated with that parent instance through method $getContext() which is automatically added to all objects in the tree. Method $setContext(context) is also available to replace the attached and inherited context at any level. Unless $setContext() is used to replace the entire context, all child objects will point to the same inherited context which allows changes to the context data at any level to be visible to all objects sharing the context.

Usage

Mongoose-context exports the following functions:

.mongoose(context)

Creates a mongoose instance with specified context attached:

var mongoose = require('mongoose');
var contexter = require('mongoose-context');
var mySchema = mongoose.Schema({ field1: String, field2: Number });
var myContext = { prop1: 123, prop2: 'abc' };
var myData = { field1: 'someText', field2: 789 };

// Create mongoose instance with custom context
var instance = contexter.mongoose(myContext);

// Use method $getContext() to retrieve the context
var context = instance.$getContext();
console.log(context === myContext); // => true

// Create a model through this instance
var myModel = instance.model('myModel', mySchema);
console.log(myModel.$getContext() === myContext); // => true

// Retrieve a model through this instance
var modelA = instance.model('myModel');
console.log(modelA.$getContext() === myContext); // => true

// Created documents will inherit context from the model
modelA.create(myData, function(err, doc) {
  console.log(doc.$getContext() === myContext); // => true
	
  // Documents retrieved through the model will also inherit the context
  modelA.findOne({field1: 'someText'}, function(err, doc) {
    console.log(doc.$getContext() === myContext); // => true
  });
});

// The context is also available in middleware
mySchema.pre('save', function(next) {
  console.log(this.$getContext() === myContext); // => true
  next();
});
var modelB = instance.model('ModelB', mySchema); 
var doc = new modelB(data);
console.log(doc.$getContext() === myContext); // => true
doc.save();	// Will invoke the pre-save middleware function

Attaching a context using a custom mongoose connection:

var mongoose = require('mongoose');
var contexter = require('mongoose-context');
var mySchema = mongoose.Schema({ field1: String, field2: Number });
var myContext = { prop1: 123, prop2: 'abc' };

// Create mongoose instance with custom context
var instance = contexter.mongoose(myContext);

// Setup custom connection
var db = instance.createConnection('my_DB_URI');

// Create a model through this connection
var myModel = db.model('myModel', mySchema);
var context = myModel.$getContext();
console.log(context === myContext); // => true

// Retrieve a model through this connection
var modelA = db.model('myModel');
console.log(modelA.$getContext() === myContext); // => true

.model(context, [db,] name, schema, collection, skipInit)

It is not required to have a mongoose instance serve as the top level parent with the context attached. If it is more appropriate for each model to have its own context, the model method can be used to attach a context to a model directly, using the normal mongoose singleton:

var mongoose = require('mongoose');
var contexter = require('mongoose-context');
var mySchema = mongoose.Schema({ field1: String, field2: Number });
var myContext = { prop1: 123, prop2: 'abc' };

// Create a model with custom context attached
var myModel = contexter.model(myContext, 'myModel', mySchema);
var context = myModel.$getContext();
console.log(context === myContext);	// => true

// Retrieve a model with custom context attached
var modelA = contexter.model(myContext, 'myModel');
console.log(modelA.$getContext() === myContext); // => true

Attach context using a custom mongoose connection:

var mongoose = require('mongoose');
var contexter = require('mongoose-context');
var mySchema = mongoose.Schema({ field1: String, field2: Number });
var myContext = { prop1: 123, prop2: 'abc' };

// Setup custom connection
var db = mongoose.createConnection('my_DB_URI');

// Create a model through this connection
var myModel = contexter.model(myContext, db, 'myModel', mySchema); 
var context = myModel.$getContext();
console.log(context === myContext);	// => true

// Retrieve a model through this connection
var modelA = contexter.model(myContext, db, 'myModel');
console.log(modelA.$getContext() === myContext); // => true

.attach(context, target)

Use this method to attach a context to an existing mongoose model created through reqular means without any context attached and not part of the inheritance tree as depicted above. This method can also be used to attach a context to queries returned by model methods such as find() and findById(). All inheritance functionality as described above will apply to this parent object and its child objects.

var mongoose = require('mongoose');
var contexter = require('mongoose-context');
var mySchema = mongoose.Schema({ field1: String, field2: Number });

// Create a 'regular' mongoose model
var myModel = mongoose.model('myModel', mySchema);
console.log(myModel.$getContext === undefined); // => true

// Create a model instance with context1 attached 
var myContext1 = { prop1: 123, prop2: 'abc' };
var myModel1 = contexter.attach(myModel, myContext1);
console.log(myModel1.$getContext() === myContext1); // => true

// Create model instance with context2 attached 
var myContext2 = { prop1: 456, prop2: 'def' };
var myModel2 = contexter.attach(myModel, myContext2);
console.log(myModel2.$getContext() === myContext2); // => true

Events

Mongoose-context generates events at various stages of context management, allowing subscribers to take custom actions whenever these events occur. Please note that some events fire everytime a document is created or retrieved so extensive custom processing could have a significant negative impact on performance.

.on('contextualized', function(target) {})

Triggered whenever a model or query is converted to a contextualized instance with a context attached. The context is accessible through target.$getContext().

.on('instantiated', function(document) {})

Triggered whenever a context has been attached to a created or retrieved document. The context is accessible through document.$getContext();

.on('contextChanged', function(target) {})

Triggered whenever $setContext has been invoked on the target to replace the attached context. Target is either a model, query or document. The context is accessible through target.$getContext();

var mongoose = require('mongoose');
var contexter = require('mongoose-context');
var mySchema = mongoose.Schema({ field1: String, field2: Number });
var myContext = { prop1: 123, prop2: 'abc' };
var myData = { field1: 'someText', field2: 789 };

// Subscribe to context events
contexter.on('contextualized', function(target) {
  console.log('contextualized triggered'); 
});
contexter.on('instantiated', function(document) {
  console.log('instantiated triggered'); 
});
contexter.on('contextChanged', function(target) {
  console.log('contextChanged triggered');
});

// Creating a model will trigger the 'contextualized' event
var myModel = contexter.model(myContext, 'myModel', mySchema)

// Returned queries trigger the 'contextualized' event as well
var query = myModel.find(); 

// Creating a document instance with either new or the create method 
// will trigger the 'instantiated' event
var doc1 = new myModel(myData);
myModel.create(myData, function(err, doc) {});

// Queries will trigger an 'instantiated' event for each retrieved document
myModel.find(function(docs) {});   

// Changing the context will trigger the 'contextChanged' event
myModel.$setContext({ field1: 'something else'});