‫Just like Express,
‫Mongoose also has the concept of middleware.
‫And so let's now learn about the first type
‫of middleware, which is document middleware.
‫Now, just like with Express, we can use
‫Mongoose middleware to make something happen
‫between two events.
‫For example, each time a new document is saved
‫to the database, we can run a function
‫between the save command is issued and the actual saving
‫of the document, or also after the actual saving.
‫And that's the reason why Mongoose middleware
‫is also called pre and post hooks.
‫So again, because we can define functions
‫to run before or after a certain event,
‫like saving a document to the database.
‫So middleware is an absolutely fundamental concept
‫in Mongoose, so just like in Express.
‫And there are tons of possibilities
‫and use cases for middleware, and we're gonna be
‫using middleware all the time in this project.
‫So there are four types of middleware in Mongoose:
‫document, query, aggregate, and model middleware.
‫And in this lecture, we're gonna talk about
‫document middleware, which is middleware
‫that can act on the currently processed document.
‫So just like the virtual properties,
‫we define a middleware on the schema,
‫so tourSchema.pre.
‫And so this is for pre middleware, which again,
‫is gonna run before an actual event.
‫And that event in this case is the save event.
‫And so this call back function that we're
‫gonna define here next,
‫so function
‫so this function will be called before an actual document
‫is saved to the database.
‫So this is document middleware,
‫and it runs, let me write all of that here.
‫So it runs before the save command
‫and the .create command.
‫But not on insert many.
‫So if we use this command here, so insertMany,
‫then that will actually not trigger the save middleware.
‫So always keep that in mind.
‫It's very important to realize that only on save
‫and on create actually this middleware here
‫is gonna be executed.
‫And so let's start by doing a simple console.log
‫and what I'm gonna log through the console is this.
‫And so in a save middleware, the disk keyword here
‫is gonna point to the currently processed document.
‫And that is the reason why it is called document middleware.
‫Again, because in this function here,
‫we have access to the document that is being processed.
‫So in this case, the document that is being saved.
‫And so let me just very quickly show that to you
‫using this console.log.
‫And so in order to now trigger this function,
‫remember we need to run a save command or a create command.
‫And so we now need to create a new tour using our API
‫in order to, yeah, to then trigger this middleware.
‫So let's go here to, to postman, and I'm gonna start by
‫by saving these two new routes that we created
‫in the previous lectures, so get monthly plan.
‫And this one here is get tour stats.
‫So now I can close them and create new tour.
‫And we specify the data here in the body.
‫Now not all of the stuff here is actually required,
‫so let's take a look at what actually is required
‫and get rid of the rest.
‫So the imageCover is required, the summary,
‫of course the price, and yeah.
‫So let's get rid of the stuff that we don't
‫really need here just to keep it at a minimum.
‫So the ratings, quantity, average,
‫so these are not necessary.
‫So I'm just gonna call this one here
‫the test tour, just to keep it really simple here.
‫Now let's send this request and indeed,
‫it created the new document and now let's take a look
‫at our console and see that document here.
‫And indeed, here it is.
‫So let's increase this here a little bit
‫and so this is what our document is looking like
‫right before it saved into the database.
‫And so here we have ratingsAverage and quantity,
‫which are set by default.
‫Remember, so 4.5 and zero, and then
‫the createdAt time stamp, and you can even
‫see the virtual property that we defined here.
‫So again, this is right before we actually
‫save this data to the database.
‫And so at this point of time,
‫we can still act on the data before it is then saved
‫to the database and that is exactly
‫what we're gonna do now.
‫So down here in our middleware function.
‫And what I wanna do here is to create a slug
‫for each of these documents.
‫So remember how in the first section,
‫we created a slug for each of the products
‫that we had in the store.
‫And so a slug is basically just a string
‫that we can put in the URL, usually based on
‫some string like the name.
‫So in this case, we're gonna create a slug
‫based here on the tour name.
‫So remember how for that we used the slugify package.
‫And so let's now go ahead and install that.
‫All right, and while that's doing,
‫let's go ahead and then require it here.
‫So require slugify.
‫Let's go back to our first window here, actually.
‫And now, down here, we no longer want
‫to log this to the console.
‫But instead we can now say this, and remember,
‫this is the currently processed document.
‫So we can now define a new property on it.
‫And that's exactly what I'm doing.
‫So this.slug should be slugify,
‫and then just a string that we want to create
‫a slug out of, and so that's gonna be this.name
‫and then we also want to pass in the option
‫that everything should be converted to lower case,
‫and so that's lower: true, and now I'll give it a save.
‫And one thing that we didn't talk about yet
‫is the next function.
‫So just like in Express, we also have the next function
‫in mMngoose middleware, basically to call the next
‫middleware in the stack as we already know.
‫Now in this case, we only have one middleware function,
‫which is why we didn't run into any problems,
‫even not calling next, but let's actually now do that.
‫And so each middleware function, in a pre save
‫middleware has access to next.
‫So that's exactly the same as in Express,
‫and so by the end of the middleware we call next,
‫and that will then call the next middleware
‫in the stack.
‫So let's try this out again.
‫And this is gonna be called test tour number two.
‫Very simple, send to sky,
‫and let's wait for it.
‫And now for some reason, it's not really here.
‫Let's see if we got some error,
‫and we actually did not.
‫But the reason why it's not working
‫is that right now we don't have any slug in our schema.
‫And remember this actually happened to us before
‫when we only had a couple of fields in the schema.
‫And when we, then we'll define some fields
‫that were not in the schema, then they were
‫simply not persisted to the database.
‫And the same thing is now happening here,
‫so we defined the slug property, but it's not in our schema.
‫And therefore it was then not saved to the database,
‫and so let's quickly fix that and let's put it,
‫oh, I don't know, it doesn't really matter,
‫can put it here right after the name,
‫so the slug should simply be a string.
‫And so that should fix it.
‫So let's go back and create the test tour number three.
‫Because it cannot be the same, because remember
‫we cannot have tours with the same name.
‫So do it again, and now indeed we have the slug property
‫right here and it is indeed based on the name,
‫as you can see here.
‫Great, so let's go back here,
‫gonna reduce this a little bit.
‫And so here we have the pre document middleware.
‫Let's now just very quickly experiment, also,
‫with a post middleware.
‫So tourSchema.post and let's use save again.
‫And then the callback function,
‫which in the case of post middleware
‫has access not only to next, but also to
‫the document that was just saved to the database.
‫So let's call that one doc and then next.
‫And so post middleware functions
‫are executed after all the pre middleware functions
‫have completed, all right.
‫So in here we actually no longer have the disk keyword,
‫but instead we have the basically finished
‫document here in doc.
‫So let's just log that finished document
‫to the console and then call next.
‫Now in this case again, we only have one
‫post middleware and so we wouldn't really need next,
‫but it's a best practice to simply always include it.
‫Now another thing that I wanted to show you
‫is that we can have, of course, multiple
‫pre middlewares or also post middlewares for the same hook.
‫And hook is what we call this save here.
‫So this middleware here is basically what we call
‫a pre save hook.
‫So you will see that terminology all the time.
‫So some call it middleware, and some call it hooks.
‫And so this is gonna be a pre save hook
‫or pre save middleware.
‫So function, and this one has access to next.
‫And so let's just log something to the console here,
‫like will save document.
‫And then next, and that of course, should be next.
‫Just to see if we get some error,
‫I'm gonna omit the next here.
‫Just to see what happens when we do not call it.
‫So I'm gonna create a new tour,
‫and by the end of this lecture I'm gonna delete
‫all of them, but for now we need them here.
‫And so now you see that it's not really finishing,
‫so we're stuck in that one middleware function
‫that doesn't have the next call.
‫So basically we're stuck in here.
‫So let's cancel the request
‫and then get it back here,
‫and try that again.
‫And so now it worked indeed.
‫So our slug is here, right,
‫and so let's take a look at our console,
‫and so indeed, our second pre middleware also run,
‫so the one logging will save document and then
‫our post middleware then logged to the console
‫the final document, and so that should also
‫already have the slug and yeah, here it is.
‫And that's actually all I had to show you
‫about document middleware.
‫Now I'm just gonna comment out these two here
‫because I don't want to pollute my log here
‫all the time with these console.logs,
‫but I'm still keeping them here, again,
‫as a reference.
‫So what I want you to remember from this lecture
‫is that we can have middleware running before
‫and after a certain event.
‫And in the case of document middleware,
‫that event is usually the save event.
‫And then in the middleware function itself,
‫we have access to the disk keyword,
‫which is gonna point at the currently being saved document.
‫And it's also very important to keep in mind
‫that this save middleware only runs for the save
‫and create Mongoose methods.
‫It's not gonna run, for example, for insert many
‫and also not for find one and update
‫or find by ID and update, which we already used before.
‫So for example, we somewhere here we have
‫we have findByIdAndUpdate, but that is not gonna trigger
‫this save middleware.
‫So that's very important to keep in mind
‫because actually a bit later in this project,
‫we will have to work around that limitation.
‫All right, so this is document middleware
‫to manipulate documents that are currently being saved.
‫Next up, we're gonna talk about query middleware.