Mongo has a sophisticated querying language with a lot of options. While there are variations of the find() method, most method calls look similar. A callback is passed as a second parameter. Scott demonstrates how to use the callback to step through, update, and delete documents.
- So Mongo has a sophisticated query syntax. I'm going to go through this one... actually this one's kind of long. But I need to go through it. I'm going to go through it relatively quicker than I normally do so we can just start with the exercise. That way you guys can get right out of here relatively earlier time and not be here all day. So I'm going to go through the notes relatively quicker until we can hop right to the example which is actually going to be kind of tough. So Mongo has a sophisticated query syntax that is full options. Actually it has too many options for me to even list here.
When I was writing this, I was worried about what to show you, what not to show you, there's so many things and there's like five different ways to do the same thing. Alright, so I was like, I don't even know what's the best way so, there's just too many things to list. So I just listed the one that I thought was the simplest and the one that I use the most and the foundation of the rest. So using a mongoose model, we have a few ways to ask mongo about what data we want. So we did this before, kind of, inside of the Mongo shell where we like DB., the name of the collection, .find.
That was the native mongo implementation. This is the mongoose implementation that just calls that internally. So when I say model, I'm talking about the name of the model. This is the model. This thing is going to export it, that's the model. So in this case it would be Post or whatever you called it when you required it. So this is the model. So model.find is a method that we can call. And what it does is it can take a few things but the most important thing is that the first object that you pass in is just like an object describing the stuff that you want to find.
In the case of Post, if we said Post.find, actually I'll just do it down here so you can see what it looks like. So down here if I were like, Post.find, the object that I can pass in as a first argument is that, is how, what type of, it's going to describe the Post I'm looking for. So I want to find the Post whose name is, or title sorry.
Whose title is whatever. So because our titles are unique, this is only going to return one. So then I can use a callback. Node style callback which takes an error, a possible error as a first argument and then a possible document as a second argument. So the document then is going to return from the database. So there I'll have that stuff. Alternatively, most of these mongo or mongoose queries return promises. So I can say .then instead.
There's also another way to execute this but we're going to talk about that later 'cause that one's a little more difficult. So that's the basics of the find method. So the find method is always going to return an array. Even if it finds one, even if it doesn't find anything, it'll be an array. But if it doesn't find anything it'll be empty. Nothing will be in array but find always returns an array. Or an error. So above is a basic example of how we can query mongo for a specific model. Using the find method, we can pass in a query object to specify what we're looking for.
The object is empty, so I have an empty object here. So that means we want to get every single thing on that model, it means give me everything on that model. Everything. I think you can even just not use the object, you can just not put anything in there. The second argument is a node style callback. In this example it's a node style callback. With either an error or the documents that's going to be retrieved. Most queries on mongoose return a promise. And you can look at the docs, it'll show you some more stuff. So here's another utility method, Model.findByID.
If you just give it an object ID, it'll find that one thing or not. So it'll either return an error, or either return that document, or it will just return nothing. No error but it also didn't find anything. So this one's very helpful for those PUT, DELETE, and GET one routes because they all use the ID property. So if you want to put something, you need an ID. So you got to find that thing first. If you want to delete something, you need an ID. So this method will come in handy for that, findById.
'Cause we'll be given the ID in the URL. Yup. - [Student] They're wondering why you're calling next if error is true. - The reason I'm doing this, so this is going to be wrapped, this is a hint of, this is actually, this query's wrapped inside of a, a route callback so we have access to request, response, and next. So because of this function, as a synchronous, if we want node to know about this error and we want to be able to catch it, we actually need to pass it to the next.
Whereas this error leaving handling before all synchronous so you'll always pass down to the chain. This is going to be in a completely different call stack. So if you're familiar with Angular, how it works, this function is happening in a completely different call stack than this execution of findById. So we have to call next in order to pass it down to our error handling or it will never get handled. It's a completely different call stack, it'll just stop and break the server. So this is why the next is awesome.
- [Student] Where's next coming from? Your name parameters or arguments? - So all this is wrapped inside of one of these. Actually I just wrote it, I'm just going to fly right into it. It's in one of these callbacks right here. When you see these examples here, they're inside of one of these functions. That's why I'm able to call response and next. Yeah, sorry about that. Next is not coming from mongoose, it's coming from express.
That's the express's next, in the middle right here. So we'll be replacing all this stuff with this stuff. So that's how you find an ID, that's how you find all of something. So those are two methods you will definitely be using. Here's a few ways to create a new document. There's probably more but here's a few ways. So we can say, var whatever equals a new model that we have. And then it'll be passed in the object to create a new model.
And all we have to do is call .save on an instance. Which also takes a node style callback with either an error or the document that got saved. And if we save it, then just send it back. Another way to do it is to use the .create shortcut on the actual model which takes in the thing that you want to create or many of those things. And then the node style callback as well, same thing. And then the third way to do it is we can just say new model without passing in an object.
And then add the properties using the dot notation. And then still call save. All three will do the same thing. The only difference is create is calling new Dog internally and then it's calling save for you. It's just doing both. Whereas we're doing it manually here. We're calling new Dog, we're adding the properties, then we're calling save. Those are three ways to create a method. - [Student] You lost me. - I lost you? - [Student] Where did dog get a function called save from? - So new Dog, when you make a new model, I'll just do it in here.
- [Student] Is that a schema? - Yeah, that's a model. - [Student] Export from the schema? - Exactly. - Okay. - So this is like one of our categories, or our Posts, or our user. So you call it new user and your post is going to return an instance. In this case it's a dog. And now we can say dog.save. If I were to come back and say user, I guess I'll delete it. Yeah, so I can just say user.save. The instance of a model is called a document and all documents have a save method on them.
It's an atomic operation. So if you call .save on a document, you will write to the database. Doesn't matter where that document is inside of node. It'll write to it. It's atomic. So those are three ways to do the same thing. You could pick your flavor. Here's a way how to update something. So we can say Model.findByIdAndUpdate, that's a real method.
You'll notice that mongoose's methods are actually pretty verbose. Like they say exactly what they mean. I'm going to find by ID and update. So if you give it an ID, and you give it the object with the new properties that you want to update to, what it will do is, first it will go see if it can find a document on this model with this ID. If it does find it, it will update these properties. And then error callback. The thing to know about this though is this thing called UPSERT.
By default if you do this, it will update the documents in these properties. It will also actually just update the documents and just be this. It will just literally be this and all the other properties that were there before will be gone. So that's not what we want. So we want to use something else to get around that. I'm not going to show you how to do that. I want you guys to figure that out. Or unless you ask me when I walk around then I'll have to show you but... - [Student] Then I'll have to show you. - I don't want to give you all answers. It's just, there's another method that allows you to do that.
Or there's like two or three other ways to do it if you literally looked it up, in like one second you'll find out. And then of course error style callback. Same thing. So like I said, most of the methods look very similar. New calls start off with something like find. You pass in some type of query object, maybe an optional update object, and then there's a callback. So there are some advanced uses and features as well. Along with performing methods on the model, we can also use the actual document to do things.
Like I was saying before, so we were talking about the .save method on the document, the document also has like a .remove method. So it can remove itself. So if you had an instance of a document and you want to delete it, you can just say document.remove and it will like, okay I'll go away. And it'll either throw an error or the removed document. So it's a quick way to delete something. There's also like a find by ID and remove or delete to do those things as well. So again, this is possible because the actual documents returned from mongo are not just objects but instances of a collection and have specific properties and methods that allow us to operate on it, and for it to be able to write back to the database.
So this is very important, the reason I emphasize this is because you're going to use this, you're going to have a document that's created somewhere else and you're going to pass it to another function and then you're going to figure out, how do I remove this thing, how do I delete this, how do I update this? And you're going to want to query the database again. You're going to want to say, I'll just do a model.find and find the document again and do it here. But you already have the document there. Just be sure that, just know that you can do these methods on the document. You don't have to query the database again.
This course was created by Frontend Masters. It was originally released on 12/30/2015. We're pleased to host this training in our library.
- Executing Node.js
- Using Express
- What is middleware?
- Testing in Node.js
- Using Mongo with Node.js
- Data modeling
- Querying data with Mongoose
- Identifying sensitive routes
- Configuring the deployment