Search code examples
mongodbmongoosemongoose-schema

How mongoose middleware works and what is next()?


userSchema.pre('save',async function(next){
   //hash the password before saving user to database
   next()
})

Hey guys I'm trying to understand the concept of middleware in mongoose. Assuming that I have an userSchema that I run the pre hook on to hash the password before saving the user to the database. On the surface, as far as I understand, the above code that I have will hash the password (not the important part for this question) and then call next() to signal that the function is done. However, I am trying to understand how things work under the hood. I want to know what is next() ? Can you guys walk me through an example of how everything works together under the hood from start to end once the code get executed or somehow help me to have a better understanding of this concept? Thanks


Solution

  • Short : with the pre method you can register listeners for certain events of your Schemas. So pre('save', callback) will fire whenever you save a document of said Model. pre means it will execute before the event, so it can be used (for example) to hash a password before saving it to the document.

    However, you have several options to define them, see below :

    The combination of using an async callback function and providing the next parameter is not necessary, you can either :

    use normal callback with next parameter

    the next parameter is a function provided to you by mongoose to have a way out, or to tell mongoose you are done and to continue with the next step in the execution chain. Also it is possible to pass an Error to next it will stop the execution chain.

    schema.pre('save', function(next) {
      // do stuff
      
      if (error) { return next(new Error("something went wrong"); }
      return next(null);
    });
    

    use async callback

    Here the execution chain will continue once your async callback has finished. If there is an error and you want to break/stop execution chain you just throw it

    schema.pre('save', async function() {
      // do stuff
      await doStuff()
      await doMoreStuff()
    
      if (error) { throw new Error("something went wrong"); }
      return;
    });
    

    Straight from the docs : https://mongoosejs.com/docs/middleware.html#pre

    Example

    const { Schema, model }  = require('mongoose');
    
    const SomeSchema = new Schema ({
      name : { type : String }
    });
    
    SomeSchema.pre('save', function (next) {
      console.log('pre save fired!');
      return next();
    });
    
    const Some = model('Some', SomeSchema);
    
    console.log('before create');
    const doc = new Some({ name : 'test' });
    doc.save((err) => {
      console.log('after saved');
    });
    

    This will output

    before create
    pre save fired!
    after saved