mongoose-consistent
Foreign reference check across collections with mongoose.
Mongoose allows models from different collections to be related by some type of reference (ref, refPath, array of ObjectIds). However, document deletion operations associated with documents from another collection, end up affecting the consistency of these relationships.
This library aims to provide mechanisms in an attempt to maintain the relational integrity between documents of different models, using their reference identifiers (_id), as well as types of action (restrict, set_null or cascade), in order to apply constraints similar to those of relational databases, however application level.
const CategorySchema = new mongoose.Schema({
name: String,
description: String,
position: Number,
})
const ProductSchema = new mongoose.Schema({
name: String,
price: Number,
category: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Category',
onDelete: 'restrict',
saveCheck(context) {
}
}
}
Supported API methods
Save | Delete |
---|
Document.save | Document.delete |
Document.update | Model.deleteOne |
Document.updateOne | |
Model.findByIdAndUpdate | Model.findByIdAndDelete |
Model.findOneAndReplace | Model.findByIdAndRemove |
Model.findOneAndUpdate | Model.findOneAndDelete |
Model.insertMany | Model.findOneAndRemove |
Model.replaceOne | Model.delete |
Model.update | Model.remove |
Model.updateOne | Model.deleteOne |
Model.updateMany | Model.deleteMany |
Query.findOneAndReplace | Query.deleteOne |
Query.findOneAndUpdate | Query.deleteMany |
Query.replaceOne | Query.findOneAndDelete |
Query.update | Query.findOneAndRemove |
Query.updateOne | Query.remove |
Query.updateMany | |
Usage
Recommended global installation only.
Note: Configure this plugin before loading models.
const mongoose = require('mongoose')
mongoose.plugin(require('@kolinalabs/mongoose-consistent'), {
eventKey: 'on_delete',
actionDefault: 'set_null',
saveCheckDefault: false
})
Options
Option | default | description |
---|
eventKey | onDelete | Change the configuration property on the schema |
actionDefault | restrict | change the default action applied when a referral is found |
saveCheckDefault | true | enable (true), disable (false) or custom (callback ) saveCheck |
Actions for delete constraint
restrict:
An error is thrown when attempting to delete a parent record.
Dispatches DeleteConstraintError instance with a similar error message:
Cannot delete a parent doc: ref constraint fails (ChildModel.parent_field)
{
onDelete: 'restrict'
}
cascade:
All child records are removed.
{
onDelete: 'cascade'
}
set_null:
Sets the referenced property in the children to null
.
{
onDelete: 'set_null'
}
no_action:
Ignore reference check.
{
onDelete: 'no_action'
}
callback:
Use a function to control the behavior of the operation.
{
onDelete(context) {
}
}
{
config: {
modelName: 'ItemB',
pathName: 'refArrayOfObjectRelated.$.itemA',
modelRefs: ['ItemA'],
action: 'cascade'
},
conditions: {
'refArrayOfObjectRelated.itemA': {
'$in': ['60c8e0c2cc629121ac49db5b']
}
},
identifiers: ['60c8e0c2cc629121ac49db5b'],
targetPath: 'refArrayOfObjectRelated.itemA',
countRef: 5
}
saveCheck for save constraint
true:
Active check during document saving.
Dispatches SaveConstraintError instance with a similar error message:
Cannot add or update a child doc: a foreign key constraint fails ('dbname'.'child_collection', CONSTRAINT 'ParentModel._id#ChildModel.parent_field' FOREIGN KEY ('parent_field') REFERENCES 'parent_collection' ('_id'))
{
saveCheck: true
}
false:
Inactive check during document saving.
{
saveCheck: false
}
callback:
Use a function to control the behavior of the operation.
{
saveCheck(context) {
}
}
{
config: {
modelName: 'ChildModel',
pathName: 'parent',
modelRefs: ['ParentModel'],
action: 'restrict',
saveCheck: true,
},
dbName: 'yourdbname',
childModel: 'ChildModel',
parentModel: 'ParentModel',
childKey: 'parent',
parentKey: '_id',
childCollection: 'child_collection_name',
parentCollection: 'parent_collection_name',
identifier: '60e630a00f29040340f556b7',
}
Note
Similar to what happens in relational databases, this configuration must occur in the child schema, corresponding to the weak side of the relationship (ex: 1:N [this side])
Configuration behavior for delete actions
Association | restrict | cascade | set_null |
---|
ref (ObjectId) | Error | document is removed | field is null |
refPath | Error | document is removed | field is null |
array of ObjectId | Error | document is removed | array item is removed |
array of Subdocuments | Error | subdocument is removed | property of subdocument is null |