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

v1.3.0

Published

Versioning module for MongoDB based in mongoose. It uses a main collection for the current data and a shadow collection for the old versions.

Downloads

1,900

Readme

Versioning Module MongoDB

Module for versioning in MongoDB, inspired by Vermongo (https://www.npmjs.com/package/mongoose-vermongo, https://github.com/codela/mongoose-vermongo and https://github.com/thiloplanz/v7files/wiki/Vermongo).

It includes support for transactions to avoid inconsistency when performing an update or deletion since this operations involve the main and the shadow collection (see instructions below).

This module allows to keep the change history of every document and the deleted documents. The idea is to have a "main collection" storing the current document versions and a different collection called "shadow collection" to keep all the past versions and deleted documents.

See Basic Usage.

Use

In order to use the package just install it as a dependency

npm install mongoose-versioned

Basic usage

This package requires mongoose and it is added as a plugin to each individual model that will be versioned. Get familiar with mongoose before using this package (https://mongoosejs.com/docs/index.html).

// import versioning and mongoose related dependencies
const versioning = require('mongoose-versioned')
const constants = require('mongoose-versioned/source/constants')

const mongoose = require('mongoose')
mongoose.Promise = require('bluebird')
let Schema = mongoose.Schema

// connect to the database following mongoose instructions, for example:
let mongodb_uri = 'mongodb://localhost/test'

const versionItems = async(mongodb_uri) => {
  try {
      await mongoose.connect(mongodb_uri, { useUnifiedTopology: true, useNewUrlParser: true, useFindAndModify: false })
      console.log("Database.connect: DB connected ")
  } catch (err) {
      console.error(`Database.connect: MongoDB connection error. Please make sure MongoDB is running:` + err.message)
      throw new Error(err)
  }

  const db = mongoose.connection

  // create the model
  let itemSchema = new Schema({
    code: { type: Number, required: true, unique: true },
    name: { type: String, required: true, unique: false }
  })

  // add the versioning plugin to the schema and specify
  // the name of the shadow collection
  const name = 'item'
  itemSchema.plugin(versioning, {collection: name + "s.versioning", mongoose})

  // instantiate the model
  let Item = mongoose.model(name, itemSchema)
  // at this point a collection named 'tests'

  // add a new document
  const newItem = {
    code: 1,
    name: "first item"
  }

  let savedItem = await new Item(newItem).save()
  console.log(`saved item with id: ${savedItem._id}, version: ${savedItem._version}`)

  let id = savedItem._id

  // update document info
  savedItem.name = "modified item"

  // add edition information
  savedItem[constants.EDITOR] = "editing user"
  
  // perform the update
  let updatedItem = await savedItem.save()
  console.log(`updated item with name: ${updatedItem.name}, version: ${updatedItem._version}`)

  // find current version
  let foundCurrent = await Item.findVersion(id, 2, Item)
  console.log(`found current version ${foundCurrent._version}, name = ${foundCurrent.name}`)

  // find old version
  let foundOld = await Item.findVersion(id, 1, Item)
  console.log(`found current version ${foundOld._version}, name = ${foundOld.name}`)

  await db.close()
}

versionItems(mongodb_uri)

Using transactions

Transactions

Transactions can be used to ensure the database remains in a consistent state even if the operation fails. Update and delete operations involve changes in both main and shadow collections and therefore need to be wrapped in a transaction to ensure serialization.

The transaction should be stated before calling the update/delete operation and in addition the session should be stored in a reserved "_session" inside the document and passed as an option to save/delete method.

const versioning = require('mongoose-versioned')
const constants = require('mongoose-versioned/source/constants')

const mongoose = require('mongoose')
mongoose.Promise = require('bluebird')

[...]

try {
  // start transaction
  session = await mongoose.startSession()
  session.startTransaction()

  // store session in the document
  document[constants.SESSION] = session

  // save sending the session as option
  await document.save({session})

  // commit transaction
  await session.commitTransaction()
  session.endSession()

} catch(error) {
  if (session) session.endSession()
  const message = `Error updating document ${id} in the collection ${collection}.`
  processError(res, error, message)
}