DEV Community

Granite Bagas
Granite Bagas

Posted on

The Story Behind mongoose-log-history: From Internal Audit Needs to Open Source

A while ago, I was working on a project where I needed to implement an audit log for some important data.

The requirements were clear:

  • Log every change to the data
  • Capture the before and after values for each field
  • Record who made the change

At first, I thought, “I’ll just manually log every data change.”
It seemed simple enough—just add some logging code wherever data was updated. I already implement something like this in different project.

But as the project grew, I realized this approach was getting messy and repetitive. Wouldn’t it be better if I could just plug in a solution and have audit logging work for any model, anywhere in the project? That’s when I decided to build a Mongoose plugin for audit logging.

Why a plugin?

  • It’s easy to add audit logging to any model—just plug it into the schema.
  • If I (or anyone else) need audit logs for other data in the future, it’s just a one-line change.
  • Maintenance and future improvements become much simpler.

So, I started building the plugin to fit my project’s needs:

  • Track changes at the field level (including arrays and nested fields)
  • Log before/after values
  • Record who made the change
  • Support soft delete, batch operations, and contextual logging

Once the plugin was working and the project was running smoothly, I thought:

“Why not add more features and open source it? Maybe other developers need this too!”

That’s how mongoose-log-history was born—a plugin you can drop into any Mongoose project to get robust, flexible audit logging out of the box.


What Does mongoose-log-history Do?

  • Automatically logs every create, update, delete, and soft delete on your Mongoose models
  • Field-level change tracking (including arrays and nested fields)
  • Batch operation support (insertMany, updateMany, deleteMany)
  • Contextual logging: add user info, approval steps, or any custom context
  • Pruning utility: clean up old logs by date or count
  • Compression support: save space for large document snapshots
  • Discriminator support: works with Mongoose inheritance
  • Manual logging API: for advanced or custom scenarios

How Easy Is It to Use?

Just add the plugin to your schema:

const mongoose = require('mongoose');
const { changeLoggingPlugin } = require('mongoose-log-history');

const orderSchema = new mongoose.Schema({
  status: String,
  tags: [String],
  items: [{ sku: String, qty: Number }],
  created_by: { id: mongoose.Schema.Types.ObjectId, name: String, role: String },
});

orderSchema.plugin(changeLoggingPlugin, {
  modelName: 'Order',
  trackedFields: [
    { value: 'status' },
    { value: 'tags', arrayType: 'simple' },
    {
      value: 'items',
      arrayType: 'custom-key',
      arrayKey: 'sku',
      trackedFields: [{ value: 'qty' }],
    },
  ],
  contextFields: ['created_by.name'],
  singleCollection: true,
  saveWholeDoc: true,
  compressDocs: true,
});

const Order = mongoose.model('Order', orderSchema);
Enter fullscreen mode Exit fullscreen mode

Now, every change to your Order documents is logged automatically!


What Does the Log Look Like?

Each log entry includes:

  • The model and document ID
  • The type of change (create, update, delete)
  • An array of field-level changes (with before/after values)
  • User/context info (if configured)
  • Full document snapshots (if enabled)
  • Timestamps

Example log:

{
  "model": "Order",
  "model_id": "60f7c2b8e1b1c8a1b8e1b1c8",
  "change_type": "update",
  "logs": [
    {
      "field_name": "status",
      "from_value": "pending",
      "to_value": "approved",
      "change_type": "edit"
    }
  ],
  "created_by": { "id": "...", "name": "Alice", "role": "admin" },
  "context": { "doc": { "created_by.name": "Alice" } },
  "created_at": "2024-06-14T12:34:56.789Z"
}
Enter fullscreen mode Exit fullscreen mode

Advanced Features

  • Soft delete support: log when a field (e.g., status: 'deleted') marks a doc as deleted.
  • Manual logging API: use getTrackedChanges, buildLogEntry, etc. for custom flows.
  • Pruning: clean up old logs with pruneLogHistory.
  • Compression: store large document snapshots efficiently.

Get Started


Feedback and Contributions

I’d love to hear your feedback, suggestions, or feature requests!

Feel free to open an issue, submit a PR, or just ⭐️ the repo if you find it useful.

Happy coding! 🚀

Top comments (0)