Wondering what’s next for npm?Check out our public roadmap! »

    mongoose-references-integrity-checker

    1.0.9 • Public • Published

    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(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(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.

    Install

    npm i mongoose-references-integrity-checker

    DownloadsWeekly Downloads

    1

    Version

    1.0.9

    License

    MIT

    Unpacked Size

    46.2 kB

    Total Files

    7

    Last publish

    Collaborators

    • avatar