Categories
MongoDB

Using MongoDB with Mongoose — Middlewares

Spread the love

To make MongoDB database manipulation easy, we can use the Mongoose NPM package to make working with MongoDB databases easier.

In this article, we’ll look at how to use Mongoose to manipulate our MongoDB database.

Update Validators Only Run On Updated Paths

We can add validators to run only on updated paths.

For instance, we can write:

async function run() {
  const { createConnection, Schema } = require('mongoose');
  const connection = createConnection('mongodb://localhost:27017/test');
  const kittenSchema = new Schema({
    name: { type: String, required: true },
    age: Number
  });
  const Kitten = connection.model('Kitten', kittenSchema);

  const update = { color: 'blue' };
  const opts = { runValidators: true };
  Kitten.updateOne({}, update, opts, (err) => {
    console.log(err)
  });

  const unset = { $unset: { name: 1 } };
  Kitten.updateOne({}, unset, opts, (err) => {
    console.log(err);
  });
}
run();

then only the second updateOne callback will have its err parameter defined because we unset the name field when it’s required.

Update validators only run on some operations, they include:

  • $set
  • $unset
  • $push (>= 4.8.0)
  • $addToSet (>= 4.8.0)
  • $pull (>= 4.12.0)
  • $pullAll (>= 4.12.0)

Middleware

Middlewares are functions that are passed control during the execution of async functions.

They are useful for writing plugins.

There are several types of middleware. They include:

  • validate
  • save
  • remove
  • updateOne
  • deleteOne
  • init (init hooks are synchronous)

Query middleware are supported for some model and query functions. They include:

  • count
  • deleteMany
  • deleteOne
  • find
  • findOne
  • findOneAndDelete
  • findOneAndRemove
  • findOneAndUpdate
  • remove
  • update
  • updateOne
  • updateMany

Aggregate middleware is for the aggregate method.

They run when we call exec on the aggregate object.

Pre Middleware

We can one or more pre middleware for an operation.

They are run one after the other by each middleware calling next .

For example, we can write:

async function run() {
  const { createConnection, Schema } = require('mongoose');
  const connection = createConnection('mongodb://localhost:27017/test');
  const kittenSchema = new Schema({
    name: { type: String, required: true },
    age: Number
  });
  kittenSchema.pre('save', (next) => {
    next();
  });
  const Kitten = connection.model('Kitten', kittenSchema);
}
run();

to add a pre middleware for the that runs before the save operation.

Once the next function is run, the save operation will be done.

We can also return a promise in the callback instead of calling next in Mongoose version 5 or later.

For example, we can write:

const { captureRejectionSymbol } = require('events');

async function run() {
  const { createConnection, Schema } = require('mongoose');
  const connection = createConnection('mongodb://localhost:27017/test');
  const kittenSchema = new Schema({
    name: { type: String, required: true },
    age: Number
  });
  kittenSchema.pre('save', async () => {
    return true
  });
  const Kitten = connection.model('Kitten', kittenSchema);
}
run();

If we call next in our callback, calling next doesn’t stop the rest of the middleware code from running.

For example, if we have:

async function run() {
  const { createConnection, Schema } = require('mongoose');
  const connection = createConnection('mongodb://localhost:27017/test');
  const kittenSchema = new Schema({
    name: { type: String, required: true },
    age: Number
  });
  kittenSchema.pre('save', async () => {
    if (true) {
      console.log('calling next');
      next();
    }
    console.log('after next');
  });
  const Kitten = connection.model('Kitten', kittenSchema);
}
run();

Then both console logs will be displayed.

We should add return to stop the code below the if block from running:

async function run() {
  const { createConnection, Schema } = require('mongoose');
  const connection = createConnection('mongodb://localhost:27017/test');
  const kittenSchema = new Schema({
    name: { type: String, required: true },
    age: Number
  });
  kittenSchema.pre('save', async () => {
    if (Math.random() < 0.5) {
      console.log('calling next');
      return next();
    }
    console.log('after next');
  });
  const Kitten = connection.model('Kitten', kittenSchema);
}
run();

Conclusion

We can add middleware for various operations to run code before them.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *