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

v1.0.0

Published

A plugin for mongoose to keep track of document changes

Downloads

2

Readme

Mongoose Footprints

A mongoose plugin to log changes in MongoDB documents made using mongoose methods. If used on Mongoose models, any changes made to that model will be logged as a document of the _Footprint model. It will contain an array that shows every change made to the document, along with the old and new document bodies.

Changes in referenced/populated documents will not be logged unless the referenced Object ID changes entirely to a different one. However changes in nested documents or subdocuments will be logged.

The plugin also supports sessions so queries in aborted transactions won't be logged.

Currently it supports the following operations:

  • Update
    • findOneAndUpdate
    • findByIdAndUpdate
    • document.save
  • Create
    • create
    • document.save
  • Delete
    • findOneAndDelete
    • findByIdAndDelete
    • findOneAndRemove
    • findByIdAndRemove

Note: The update operations will set new: true as the default so the returned object will always be the updated object.

Example document

Get Started

Install the package

npm i mongoose-footprints

Then, just use the plugin on the schema before you make a model from it.

Book.js

const footprints = require('mongoose-footprints');
const mongoose = require('mongoose');

const bookSchema = mongoose.Schema({
  name: String,
  author: String,
});

const options = {
  operations: ['update', 'delete'],
  logUser: false,
};

bookSchema.plugin(footprints.plugin, options);

const Book = mongoose.model('Book', bookSchema);

Possible plugin options you can pass are given below. They are passed inside an object.

Plugin Options

  • logUser: true / false - To log the user who updated the document. If set to false, the default user logged is System. If set to true, the user has to be passed in the options of the query. Otherwise, it will be recorded as Unknown. Default is false.
  • operations : ['update', 'create', 'delete'] - The operations that will be logged. Default is ['update'].
  • storeDocuments: true/false - Store the entire old document and updated document inside the footprint along with the list of changes. Set it to false if it causes you to exceed the maximum document size of MongoDB. Default is true.

You can pass in extra options during mongoose queries that are specific to that operation.

Query Options

  • footprint: true / false - Set it to false to not create a footprint of this query. Default is true.
  • user: mongoose.Schema.Types.Mixed - Can be any data type. This will log the user who made this change. Default is System if logUser is set to false, otherwise it is simply Unknown.

Example Usage

findOneAndUpdate()

await Book.findOneAndUpdate(filter, updates, {
  user: req.user,
  session: session,
});

create()

const bookObject = {
  name: 'Angels & Demons',
  author: 'Dan Brown',
};

// to use Model.create() with options, the document has to be passed in an array
// see https://mongoosejs.com/docs/api/model.html#model_Model-create
const doc = (
  await Book.create([bookObject], {
    footprint: false, // setting to false will not log this creation
  })
)[0];

save() when updating

let savedBook = await Book.findById(doc._id);
savedBook.name = 'The Da Vinci Code';
await savedBook.save({
  footprint: true, // already true by default though
});

save() when creating

const book = new Book({ name: 'Angels & Demons', author: 'Dan Brown' });
await book.save({ user: req.user });

findOneAndDelete()

await Book.findOneAndDelete(filter, {
  session: session,
});

Finder Methods

There are also some utility methods that can be used to query for footprints. The parameters are similar to that of the find() method of mongoose:

  • getFootprints(filter, projection, options, callback)
  • getCreations(filter, projection, options, callback)
  • getDeletions(filter, projection, options, callback)
  • getUpdates(filter, projection, options, callback)

Example Usage

const footprints = require('mongoose-footprints');

await footprint.getFootprints({ documentId: doc._id });

Footprint Model

{
  modelName: String,
  documentId: mongoose.Schema.Types.ObjectId,
  oldDocument: {},
  newDocument: {},
  user: mongoose.Schema.Types.Mixed,
  changes: [String],
  typeOfChange: {
    type: String,
    enum: ['Create', 'Update', 'Delete'],
    default: 'Update',
  }
}

Future Plans

  • Not satisfied with how changes in arrays are documented. I have plans to make the logging much more extensive for this kind of data type.
  • Test cases don't cover all sorts of scenarios at the moment, so I'll need to think of more. Currently only the core features are covered.