Introduction to MongoDB Introduction to MongoDB

Middleware Hooks: Pre, Post & Async

Check out a free preview of the full Introduction to MongoDB course:
The "Middleware Hooks: Pre, Post & Async" Lesson is part of the full, Introduction to MongoDB course featured in this preview video. Here's what you'd learn in this lesson:

Scott discusses how to utilize pre-save, pre-validation, and post-save middleware, among many available. An example is given on making the code asynchronous, and Scott answers a question about how the library determines that the code is asynchronous without using flags.

Get Unlimited Access Now

Transcript from the "Middleware Hooks: Pre, Post & Async" Lesson

[00:00:00]
>> Scott Moss: Sweet, some of the other stuff I wanna show is hooks. So someone asked a question about how do we get notifications or how do we know when something happens on a collection, and then respond to it. Well Mongoose's answer to that is hooks. So we can hook into, or actually they call them middleware, I call them hooks, but the official name is called middleware.

[00:00:21] So what you can do is you can add middleware into different events that happen on the collection. And pretty much an event is any operation that could happen. You do a find, a find one and delete, a save, a remove, all those different types of operations you can do on a model, you can either tie into them before they happen or after they happen, and it can be synchronous or asynchronous.

[00:00:46] And you could even control the order when they happen. And that's what the middleware allows you to do. So it's actually, middleware by itself is really advanced, but I was just gonna show you some of the stuff that you can do. So for instance, if I wanted to run middleware before I created a school, before it was actually saved in the database, I wanna run some middleware, what I can do is I can use the same schema object that we created from mongoose.schema, and what I can do is I can say school.pre.

[00:01:16] So if I do pre, and then I pass in the name of the event that I want to subscribe to, I'm going to say pre save, I can run some functionality in here. So in this case I'm just going to say console.log(before save), save there we go. So I'm just going to do that.

[00:01:46] And none of our school stuff is unique or required, so I can just run the same code, and we should still see it. So I'm gonna get rid of these other logs.
>> Scott Moss: Still gonna save it, so if I run this,
>> Scott Moss: You can see I get a log before a save.

[00:02:02] So this happened before the actual document was saved. This did not happen before the validation. If we had validations on the document and I was trying to fix them inside of the save, it would still fail because validations run before save. There's another hook for that and that's prevalidate.

[00:02:18] So if you want to run things before Mongoose validates then you can say before you validate anything, let me do my validation first, and then you can do your thing. So this is a great place to do everything that's custom validations and stuff like that. And again, pretty much for almost any operation that you can do on a model, there is a hook for it, or a middleware for it.

[00:02:38] So if you want to do before find one, you can say before find one. And whenever the find one query runs, it's gonna run this function first. If you wanna do one before find one and remove, you can add that. Almost any operation you can do that. There's some small gotchas between querying and updating and how that works, and what you would get, but it's very minute, and you just have to look at the documentation of what those small ones are because it really depends on how your stuff is set up.

[00:03:11] But basically you either might get a reference to a document as this, or you might get a reference to the update that's coming in. It really depends on how you structure your application. And those are the only things, but just to be safe, don't use the arrow functions, just use the regular functions to make sure that the binding is correct.

[00:03:29] So that's for pre, for post it's mostly the same thing. So I can do post save.
>> Scott Moss: And I can say after save check this out. So I'm going to do this and then, boom, after save it ran.
>> Scott Moss: So these were just synchronous middleware functions, you can also do asynchronous.

[00:03:53] So if you wanted to do asynchronous then, and if you're just doing saves and read, then you're gonna get two arguments. So you'll probably get the documents, the first argument, and I believe you'll get this other one called next or, actually,I think next is the only one you'll get.

[00:04:08] So you'll get next as one argument like this, and then now you can do asynchronous stuff in here. So if I wanted to say let's just do a setTimeout here. So we'll say setTimeout for 300 and then we'll do a console.log.
>> Scott Moss: And then we'll say next as in we're done.

[00:04:33] So next is a function, that you can say, all right, I'm finally done, you can go onto the next middleware in the stack. Cuz you can stack up these middleware and whenever you create them, that's the order they're going to be executed, so saying next is saying go to the next middleware, I'm done now, and that's what that function is for.

[00:04:49] So if you ever use middleware in Express or any other server framework, it's very much the same way, just saying go to the next middleware that's registered. Cuz there's nothing stopping me for making another school.post('save'). I can do that again, there's no one stopping me from doing it, but this one will run first then this one.

[00:05:07] And this is saying, all right, I'm done, go to the next one, but not before I do 300 milliseconds. So, we'll do that, run this. Okay, yeah, I had it right the first time. So doc will be the first argument and then next will be the next argument, doc is gonna be the instance of the document itself.

[00:05:26] So if I said doc, like that.
>> Scott Moss: There we go. So now we have a post save, it waited 300 milliseconds, and then I logged off the docket, which was the first argument.
>> Scott Moss: And actually, I'll just make that a little longer, so we can actually see it, cuz that happened kinda fast.

[00:05:51]
>> Scott Moss: There we go. So I'm using asynchronous stuff in here, which means you can do other database stuff inside of this middleware, which is really helpful, and that's actually what you're gonna be doing next. So we had a question earlier was like, well, if we're doing these associations and I delete something but now the model that's referred to some of this is deleted, how do I clean that up?

[00:06:10] You would do it in this middleware. So if you delete something, you need to go query the database for all the things that are referencing it and delete the reference too, or whatever you do there. So this is where you would do that. Or this is where I would do it, I'm sure you can do it somewhere else, but this is what this is built for.

[00:06:29]
>> Scott Moss: Any questions on middleware?
>> Scott Moss: Yes.
>> Speaker 2: Did we have to do anything to denote that it was gonna be asynchronous or did just-
>> Scott Moss: Yeah, or I was going to answer that question, yes, kind of crazy how that works. So note a lot of libraries what they'll do is, basically the short answer is they look if you ask for the argument.

[00:06:53] If you ask for two arguments, they know it's asynch. That's what they do. So if you say, yeah, I asked for two arguments, so therefore it's asynch. If I only asked for one argument, it won't be asynch. So they look at the like arity of the arguments. I don't really like that style programming.

[00:07:09] I don't know why people do that in JavaScript, but it's something people used to do back in the day and it's carrying over. I really don't like that, I like to be just explicit, like I like to pass in a flag or maybe just return a promise, like everybody else does, but yeah, if you put two arguments here, then that's how they know.

[00:07:27] Yeah, otherwise it's like what is that? It's magic. Yeah, any other questions?
>> Scott Moss: Pretty powerful stuff. Another good example for middleware is if you're doing real time with WebSockets or anything like that, this is a great place to update all your clients, all right. So if one client updates a chat, right, and you need to post that chat message to everybody else's chat, you would do that in something like this, like post save, ping everybody else's chat room with this thing.

[00:08:00] So, it's a great place for stuff like that, very, very helpful.