Skip to content

A mongoose plugin to take diffs and history of your MongoDB documents and manage its versions.

License

Notifications You must be signed in to change notification settings

borodayev/mongoose-history-diff

Repository files navigation

mongoose-history-diff

travis build codecov coverage npm Commitizen friendly Greenkeeper badge semantic-release

This is a mongoose plugin for tracking the history and differences of your MongoDB documents. The differences related to one particular model will be stored in a separate MongoDB collection.

Installation

yarn add mongoose-history-diff
npm i mongoose-history-diff

Usage

Add plugin to your Mongoose schema:

import DiffPlugin from 'mongoose-history-diff';
CoderSchema.plugin(DiffPlugin, {
    orderIndependent: true,
    diffCollectionName: 'my_diffs', 
});

orderIndependent option defines whether the order of elements in an array is important or not. If true then it won't create a new diff in case new changes occurred. By default false.

diffCollectionName option sets the name of a collection with diffs. If not provided ${parent_collection_name}_diffs will be used.


Here is an example of how would look a diff doc after changing a string field:

// initial state
{
  _id: "5f8c17fabb207f0017164033",
  name: "John Doe",
}
// after changes
{
  _id: "5f8c17fabb207f0017164033",
  name: "John Smith",
}
// diff doc
{
  dId: "5f8c17fabb207f0017164033",
  v: 1,
  createdAt: "2020-10-18T10:25:27.279Z",
  c: [
    {
      p: ["name"],
      k: "E",
      l: "John Doe",
      r: "John Smith",
      i: null
    }
  ]
}

Diffs are represented as one or more change records (c field in the doc above). Change record has the following structure:

  • k - indicates the kind of change; will be one of the following:
    • N - indicates that a new field/element was added.
    • D - indicates that a field/element was deleted.
    • E - indicates that a field/element was edited.
    • A - indicates a change within an array.
  • p - the field's path in the original document.
  • l - the value before changing (undefined if k === 'N').
  • r - the value after changing (undefined if k === 'D').
  • i - when k === 'A', indicates the index in an array where the change has occurred.
  • it - when k === 'A', contains a nested change record of an array element with index i.

You could exclude specific fields from tracking by adding track_diff: false configuration to your field definition inside the Mongoose schema:

export const CoderSchema: MongooseSchema<CoderDoc> = new mongoose.Schema(
 {
   name: {
     type: String,
     track_diff: false,
   },
   skills: [
     {
       name: { type: String }
     },
   ],
 {
   timestamps: true,
 }
);

The _id field is excluded from the tracking by default.


Also, the plugin will add a static diffModel method to the original model that returns the model of diff collection.

import { type IDiffModel } from 'mongoose-history-diff';
const CoderDiffModel: IDiffModel  = Coder.diffModel();

This model contains several static methods (types could be found here):

  • createDiff method is using internally for creating new diffs, but also exposed in case there will be a necessity to manually save diffs.

    createDiff(dId: ObjectId, v: number, changes: ChangeDoc[]): Promise<IDiffDoc>;
  • findByDocId method is using for finding all diffs related to a particular document.

    findByDocId(dId: ObjectId): Promise<Array<IDiffDoc>>;
  • findAfterVersion method is using for finding all diffs related to a particular document after specific version.

    findAfterVersion(dId: ObjectId, v: number): Promise<Array<IDiffDoc>>;
  • findBeforeVersion method is using for finding all diffs related to a particular document before a specific version.

    findBeforeVersion(dId: ObjectId, v: number): Promise<Array<IDiffDoc>>;
  • revertToVersion method is using for reverting a particular document to a specific version.

    revertToVersion(d: Object, v: number): Promise<any>;
  • mergeDiffs method is using for getting merged diffs of a particular document among several versions.

    mergeDiffs(doc: Document, opts?: MergedDiffsOptsT): Promise<Array<RawChangeT>>;

License

MIT