0.3.2 • Published 3 years ago

@kolinalabs/mongoose-consistent v0.3.2

Weekly downloads
2
License
Apache 2.0
Repository
github
Last release
3 years ago

mongoose-consistent (v2)

Foreign reference check across collections with mongoose.

travis npm downloads

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

Check the sample project

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',      // onDelete (default)
        actionDefault: 'set_null',  // restrict (default)
    })

Options

Optiondefaultdescription
eventKeyonDeleteChange the configuration property on the schema
actionDefaultrestrictchange the default action applied when a referral is found

Actions

restrict:

An error is thrown when attempting to delete a parent record.

{
  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) {
      // console.log(context)
  }
}

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)

// Author write post
const PostSchema = new mongoose.Schema({
    title: String,
    content: String,
    author: {
        type: mongoose.Types.ObjectId,
        ref: 'Author',
        onDelete: 'restrict'    // cascade/set_null/no_action
    }
})

Supported reference types

ref

const PostSchema = new mongoose.Schema({
    title: String,
    content: String,
    author: {
        type: mongoose.Types.ObjectId,
        ref: 'Author',
        onDelete: 'restrict'
    }
}, { timestamps: true })

refPath

const CommentSchema = new mongoose.Schema({
    body: String,
    target: {
        type: mongoose.Types.ObjectId,
        required: true,
        refPath: 'forModel',
        onDelete: 'set_null'
    },
    forModel: {
        type: String,
        required: true,
        enum: ['Post', 'Product']
    }
})

array of ObjectId

const ProductSchema = new mongoose.Schema({
    name: String,
    price: Number,
    tags: [{
        type: mongoose.Types.ObjectId,
        ref: 'Tag',
        onDelete: 'cascade'
    }]
})

CHANGED! When using the action type cascade in such a configuration, only the subdocument is removed from array.

CHANGED! The ObjectId removed from array

Unlike what happens with a direct property, which is referenced in a unique way to the document, in arrays, several types of identifiers can be associated with the parent document, thus, it becomes relevant to just cancel the corresponding ids, keeping others associated with the document. , without removing it.

When using the action type set_null in such a configuration, the ObjectId removed from array.

Subdocuments

According to the mongoose documentation - Subdocuments are documents embedded in other documents.

This lib provides functionality so that you can treat references with subdocuments (at any level), just as it does with the common reference between first level documents.

// This will be a product subdocument
const DataSheetSchema = new mongoose.Schema({
    power: Number,
    weight: Number,
    width: Number,
    height: Number
}, { timestamps: true })

const ProductSchema = new mongoose.Schema({
    name: String,
    price: Number,
    // tags: [{
    //     type: mongoose.Types.ObjectId,
    //     ref: 'Tag',
    //     onDelete: 'restrict'
    // }],
    datasheet: DataSheetSchema  // << is here
}, { timestamps: true })

const CommentSchema = new mongoose.Schema({
    body: String,
    target: {
        type: mongoose.Types.ObjectId,
        required: true,
        refPath: 'forModel',
        onDelete: 'restrict'
    },
    forModel: {
        type: String,
        required: true,
        enum: [
            'Post',
            'Product', // In addition to the standard reference to the parent document
            'Product.datasheet' // A subdocument can be used as a reference
        ]
    }
})

The above example uses the refPath mapping strategy, however two other forms (ref or array of ObjectIDs) are also supported.

Configuration and behavior matrix

Associationrestrictcascadeset_null
ref (ObjectId)Errordocument is removedfield is null
refPathErrordocument is removedfield is null
array of ObjectIdErrordocument is removedarray item is removed
array of SubdocumentsErrorsubdocument is removedproperty of subdocument is null

Running tests

  • Copy '.env.example' file to '.env'
  • Configure your mongodb dsn (full)
  • Run 'npm test'
0.3.0

3 years ago

0.3.2

3 years ago

0.3.1

3 years ago

0.2.7

3 years ago

0.2.8

3 years ago

0.2.1

3 years ago

0.2.0

3 years ago

0.2.6

3 years ago

0.2.3

3 years ago

0.2.2

3 years ago

0.2.5

3 years ago

0.2.4

3 years ago

0.1.8

4 years ago

0.1.7

4 years ago

0.1.6

4 years ago

0.1.5

4 years ago

0.1.4

4 years ago

0.1.3

4 years ago

0.1.2

4 years ago

0.1.0

4 years ago