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-references-integrity-checker

v1.0.9

Published

Package useful for mantaining the references structure of mongoose models. Supporting soft delete.

Downloads

10

Readme

Package: mongoose-references-integrity-checker

Package useful for mantaining the references integrity and structure of mongoose models. It provides cascade deleting, and ref support at any nested level. Also include support for soft deleting.

N.B: This is based on middleware hook remove and deleteOne of mongoose. If you would like to mantain the integrity anyway, you should always use this middleware even on a bunch of data (obviously at the cost of performance) by looping over the collection and deleting singularly every document.

If you are interested in the integrity of sub references too, watch this out.

Dependencies

Mongoose >= 5.10.7, MongoDB >= 3.6

Install

For this package :

npm i mongoose-references-integrity-checker

If you would like to integrate it with soft deleting:

npm i mongoose-references-integrity-checker mongoose-soft-deleting

Setup

For setting up the integrity checker on a mongoose schema, you have two options:

const referencesIntegrityChecker = require('mongoose-references-integrity-checker');

const TestSchema = new mongoose.Schema({});
referencesIntegrityChecker('Test', TestSchema);
const TestModel = mongoose.model('Test', TestSchema);
const { consistentModel } = require('mongoose-references-integrity-checker');

const TestSchema = new mongoose.Schema({});
const TestModel = consistentModel('Test', TestSchema);

Concepts

Reference States

A reference could stay in three possible states:

  • Required ( Deleting the parent of the relationship will throw an error )
  • Required and Cascade ( Deleting the parent of the relationship will delete all of his children )
  • Not required ( Deleting the parent will unset the ref on all of his children )

Required

Setting up the models in this way :

const { consistentModel, RefConstraintError } = require('mongoose-references-integrity-checker');

// House - 1
const HouseSchema = new mongoose.Schema({});
const HouseModel = consistentModel('House', HouseSchema);

// Room - N
const RoomSchema = new mongoose.Schema({
  house: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'House',
    // Only required
    required: true,
  },
});
const RoomModel = consistentModel('Room', RoomSchema);

...

// Setup parent and child
const parent = await new HouseModel().save();
const child = await new RoomModel({ house: parent._id }).save();

try{
// Try delete
await parent.deleteOne();
}catch(e){
    assert(e instanceof RefConstraintError);
}

Would lead in the situation in which when you delete the parent on the relationship (e.g. House) then will be thrown a RefConstraintError.

The reference is required on the child of the relationship, so you can't delete the parent without unsetting the reference first.

Required and Cascade

Consider this situation:

const { consistentModel, RefConstraintError } = require('mongoose-references-integrity-checker');

// House - 1
const HouseSchema = new mongoose.Schema({});
const HouseModel = consistentModel('House', HouseSchema);

// Room - N
const RoomSchema = new mongoose.Schema({
  house: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'House',
    // Required and cascade
    required: true,
    cascade: true
  },
});
const RoomModel = consistentModel('Room', RoomSchema);

...

// Setup parent and children
const parent = await new HouseModel().save();
const child0 = await new RoomModel({ house: parent._id }).save();
const child1 = await new RoomModel({ house: parent._id }).save();

// Delete
await parent.deleteOne();

// All deleted
assert(!await HouseModel.findById(parent._id));
assert(!await RoomModel.findById(child0._id));
assert(!await RoomModel.findById(child1._id));

Deleting the parent of the relationship will delete all his children.

Not Required

This is the last use case :

const { consistentModel, RefConstraintError } = require('mongoose-references-integrity-checker');

// House - 1
const HouseSchema = new mongoose.Schema({});
const HouseModel = consistentModel('House', HouseSchema);

// Room - N
const RoomSchema = new mongoose.Schema({
  house: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'House',
    // Not required
    required: false,
  },
});
const RoomModel = consistentModel('Room', RoomSchema);

...

// Setup parent and child
const parent = await new HouseModel().save();
const child = await new RoomModel({ house: parent._id }).save();

await parent.deleteOne();

// Ref on child will be null
assert(!child.house);

If the reference is not required then deleting the parent of the relationship will unset the ref on all his children.

Nesting

In the last examples we've seen the most simple case, in which the ref on the child is in the root of the document. Any way you can nest it in the way you prefer and the usage will be the same.

const RoomSchema = new mongoose.Schema({
  pathToRef: {
    ...
        {
            anyProp: [
                ...
                    propertyIfYouWant: {
                        type: mongoose.Schema.Types.ObjectId,
                        ref: 'House',
                        ... (refOptions)
                    }
                ...
            ]
        }
    ...
  },
});

Soft Delete

Optionally you can combine the usage of the library mongoose-soft-deleting with this package.

The behaviour in this case will be about the same with some differences.

Required

If you try to soft delete the parent of the relationship, then will be thrown the same RefConstraintError as before.

const { consistentModel, RefConstraintError } = require('mongoose-references-integrity-checker');
const softDeletePlugin = require('mongoose-soft-deleting');

// House - 1
const HouseSchema = new mongoose.Schema({});
HouseSchema.plugin(softDeletePlugin);
const HouseModel = consistentModel('House', HouseSchema);

// Room - N
const RoomSchema = new mongoose.Schema({
  house: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'House',
    // Only required
    required: true,
  },
});
RoomSchema.plugin(softDeletePlugin);
const RoomModel = consistentModel('Room', RoomSchema);

...

// Setup parent and child
const parent = await new HouseModel().save();
const child = await new RoomModel({ house: parent._id }).save();

try{
  // Try soft delete
  await parent.softDelete(true);
}catch(e){
    assert(e instanceof RefConstraintError);
}

Required and cascade

If you try to soft delete or restore the parent of the relationship then all his children will have the same fate.

const { consistentModel, RefConstraintError } = require('mongoose-references-integrity-checker');
const softDeletePlugin = require('mongoose-soft-deleting');

// House - 1
const HouseSchema = new mongoose.Schema({});
HouseSchema.plugin(softDeletePlugin);
const HouseModel = consistentModel('House', HouseSchema);

// Room - N
const RoomSchema = new mongoose.Schema({
  house: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'House',
    // Required and cascade
    required: true,
    cascade: true
  },
});
RoomSchema.plugin(softDeletePlugin);
const RoomModel = consistentModel('Room', RoomSchema);

...

// Setup parent and children
const parent = await new HouseModel().save();
const child0 = await new RoomModel({ house: parent._id }).save();
const child1 = await new RoomModel({ house: parent._id }).save();

// Delete
await parent.softDelete(true);

// All soft deleted
assert((await HouseModel.findById(parent._id)).isSoftDeleted());
assert((await RoomModel.findById(child0._id)).isSoftDeleted());
assert((await RoomModel.findById(child1._id)).isSoftDeleted());

// Restore
await parent.softDelete(false);

// All restored
assert(!((await HouseModel.findById(parent._id)).isSoftDeleted()));
assert(!((await RoomModel.findById(child0._id)).isSoftDeleted()));
assert(!((await RoomModel.findById(child1._id)).isSoftDeleted()));

Not required

If you try to soft delete the parent of the relationship then only the parent will be soft deleted. The child will still have his reference set to the parent (because even if the parent is soft deleted, it still exists).

const { consistentModel, RefConstraintError } = require('mongoose-references-integrity-checker');
const softDeletePlugin = require('mongoose-soft-deleting');

// House - 1
const HouseSchema = new mongoose.Schema({});
HouseSchema.plugin(softDeletePlugin);
const HouseModel = consistentModel('House', HouseSchema);

// Room - N
const RoomSchema = new mongoose.Schema({
  house: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'House',
    // Not required
    required: false,
  },
});
RoomSchema.plugin(softDeletePlugin);
const RoomModel = consistentModel('Room', RoomSchema);

...

// Setup parent and child
const parent = await new HouseModel().save();
const child = await new RoomModel({ house: parent._id }).save();

await parent.deleteOne();

// Ref on child will be the same
assert(child.house.equals(parent._id));

Test

You can try the tests using the following command ( before you need to change the connection to MongoDB ) :

npm install --test
npm run test

Support

If you would like to support my work, please buy me a coffe ☕. Thanks in advice.