API Design in Node.js (using Express & Mongo) Exercise 8 Solution
This course has been updated! We now recommend you take the API Design in Node.js, v4 course.
Transcript from the "Exercise 8 Solution" Lesson
>> Speaker 1: User model like I said, all it has is a username. This type is string, it's unique, it's also required. Done, all right. So if we wanted username to be, or actually let's just keep username. And let's say we wanted to also have a first name or let's say we wanted to have an address for the user, right?
[00:00:30] And we want it to be an object because somebody brought this up. How do we know if it's a nested object or how to we know just defining the type? So if I had an address, what I'm about to do now is gonna different from what's up here.
[00:00:46] This is just saying I only have a property, its value is a string and it's validated by this. But by coming out here saying, hey, I have an address and it also has a state property, just by doing that or I'll just say string. I'm now telling Mongoose that, address is actually an object, and it has a state property whose type is string.
[00:01:08] Just by doing that. But if I did this, type: String, it now is like, address is not an object. It's actually a string. You see the difference? It's the keyword type. That's what I'm trying to say. The keyword type is saying, like okay, actually address is a string.
[00:01:32] Whereas this is like, no, no, address is an object and has a state. It was a string. And then for the state, we can do, yep, it's a string, or I'm sorry.
>> Speaker 1: And it's required and you can do all that stuff too, but then you're like, now you're defining like another schema almost and you can just have a state schema somewhere else and bring it in here, which would probably be better, nested documents.
[00:01:59] So you could do that. Also the other thing is what if you wanted to use the type property for the property name? What if the user schema had a type name, like it had a property called type. So I was like, yeah, it's type. And I'll put string.
[00:02:16] That's not gonna work because that's the keywork type. So a way to get around that, you'd have to use an object literal and then you have to put type again, just like we did up top, and then say String. So that means I have a property called type whose type is String, if you wanted that.
>> Speaker 1: Or just not use the word type for strings. You got a question, Mark?
>> Speaker 2: There was a question that came up. They're using nodeman and they kept reasserting the server. Do they keep open ten concurrent connections?
>> Speaker 1: No, no, when it stops, when the server stops, the database will stop, yeah.
>> Speaker 2: And then the other one. Should Mongo fields never reference Mongoose keywords?
>> Speaker 1: That's a good way to live. I've always lived that way and it worked out for me. So, yes, I would not have my fields reference keywords, just to avoid that. Just come up with another name.
[00:03:26] But if you absolutely have to use the keyword, then I think the go-to is to do something like this. You give it the name, make sure you create the object literal syntax, and then you specifically say its type and that, I think that will escape any type of keyword reservation in Mongoose.
[00:03:45] But to completely avoid it, just don't use it. Any questions on this one? This is pretty straightforward. It's a user collection, which will be users collection, get the schema, export it. Post-model, this is a little bit crazier, so string. The title is a string. It's required and it's also unique.
[00:04:11] The text or the content of the blog, I decided not to make it unique. If you made it unique, that's fine. Type string required true. And then for author, that should not be an array. I don't why that's an array. Should just be an object and its type is, let me put this on another line, there we go.
>> Speaker 1: Cool, its type is gonna be Schema.Types.ObjectID. The reason I put schema here cuz I already set for our schema equals Mongoose.Schema. If you didn't do that then it'll be mongoose.Schema.Types.ObjectID. I just aliased it up here as that. So Types.ObjectId is its type, its reference is gonna be the user collection that we made here.
>> Speaker 1: I guess this should also be required too.
>> Speaker 1: And then categories is gonna be an array of object IDs whose reference is the category model or the category collection I should say. We don't have to put unique here. Just like we didn't have to put unique here because the object id's are already unique.
[00:05:45] We don't have to specify that the things must be unique because they're already guaranteed to be unique, cuz that's what Mongo does, creates unique object IDs. So if it didn't do that very well, I don't think we would be using it today.
>> Speaker 1: It wouldn't exist. Nobody would use it.
[00:06:02] That's like one thing a database should do very well, is make unique IDs. Cool, any questions on what's going on in here?
>> Speaker 1: Nope. Okay. And then category model, pretty simple, it's got a name, String, required, true, unique, and then register category. One thing I did want to talk about, though, in the post model was the different types of relationships that are going on.
[00:06:30] All right, so I've mentioned it a little bit. So, alternatively we could have did the inverse or we could've did both actually. So, right now the post schema knows about the author who wrote it or the user who wrote it, but the user knows nothing about the post that it created.
[00:06:50] All right, so how would I know what post the user has written? If I wanted let, go, look at the user's profile. Like, all right, here's all the block post this user has written, how would I know that? Does anybody know? Anybody's ever used databases?
>> Speaker 2: So the problem has reference back to the user.
>> Speaker 1: Exactly. Post model has a reference back to the user, so I would just go to the post and be, give me all the post who has an author, whose object ID is this. All right, and it'll give you back all the posts. The user doesn't need to know what post it made, but if I decided to do that, if I just came in here and was like, you know what?
[00:07:28] You're also gonna have an array of post IDs, right, and you're gonna be objects, ref, posts and objectID.
>> Speaker 1: All right, so if I did that, does anybody know what that's called, what I just did?
>> Speaker 2: Inverse association?
>> Speaker 1: Inverse association? Yeah, I wouldn't even think of that, but yeah, that's true.
[00:07:59] There's another term that I'm looking for. So specifically relational databases.
>> [INAUDIBLE] [INAUDIBLE] [INAUDIBLE]
>> Speaker 1: It's denormalization, right? I just denormalized the data. It was normalized before cuz there was only one way for me to access a certain type of data. Now there's two ways for me to access the same data.
[00:08:23] So now I can ask the users about, where are your posts, and now I can ask the posts about where your users are, so it's two ways to get the same data. All right, so that's a common thing, people will set up their databases and then when things get crazy they'll just come in and they'll just denormalize it, all right.
[00:08:38] So you could do that, but I recommend not doing this because, let's just think about this. So if we just have one user in here who made ten posts, let's just think about that. The user made ten posts, and I come and create a UserSchema for that one user, and I also wanna populate all the posts.
[00:08:56] Populate means put all the posts, get the references for these posts, and actually place them in this array. It'll actually go get the post objects, and place them in here. And if I did that, and that's the only stuff I had in my database, just by asking that one user for all its posts, I now just pulled the entire database.
>> Speaker 1: That's the entire database, that one user and all its 30 posts, the entire database. The same thing could be said if I did the inverse. So if I got rid of this and I was on the post model and all I had on here, sorry. The same couldn't be said for this, is because it's the one to many relationship.
[00:09:37] So because of the one to many relationship, whereas post is the many side and user is the one side, it's better to put the reference on this side. So that way now, let's say I have 30 posts in my database and only one user, if I go to the post, I'm like, all right, I wanna get this post, and I also wanna populate the user, and I pull that down, I'm not pulling the entire database, cuz there's still 29 other posts that don't belong to this user.
[00:10:02] Whereas the other side, if I did do that, it would be the entire database.
>> Speaker 1: Guys, get what I'm saying there? Okay, so small things, just databasing in general. I just wanna talk about that. Great. So any questions on the schemas that we made and the relationships between them?
[00:10:22] So again, we have a one to many relationship with the authors. So a user can have many posts, but a post can only belong to one user.
>> Speaker 2: Wouldn't you want a reference to category in the posts?
>> Speaker 1: Would we want a reference to category? Would we not, or would we?
>> Speaker 2: You have one there?
>> Speaker 1: Yeah.
>> Speaker 2: We have one there, yeah. [CROSSTALK] I'm sorry.
>> Speaker 1: Yeah.
>> Speaker 2: Nevermind.
>> Speaker 1: Right, yeah. So, we definitely wanna put the reference to the categories in the post and not the other way around. We don't wanna put them here. Right? Cuz then it would be like, that would just be tough.
>> Speaker 1: Scott.
>> Speaker 2: Yeah.
>> Speaker 1: Json example for posts.
>> Speaker 2: Yes. You have an array of three object ids. How would you specify that in a schema that you can only have three?
>> Speaker 1: Good question. So the syntax is very confusing there, right. And it's not only three, I just put three in there.
[00:11:10] It's an arbitrary number. I just wanted to show you that you can have- The requirements say- [CROSSTALK] That's very true, I just wanted to show you that it can be multiple, but it definitely isn't three. So, when you have this array here, and then you just place in this object describing the type, that means, it's not saying you can only have one here.
[00:11:29] It's just saying that whatever goes in here must look like this. This is the blueprint for what anything that comes in this array, that's what that means. So, you can have as many as you want. Yeah, good question.
>> Speaker 1: Any other questions? Yo.
>> Speaker 2: Can you do regular expressions and it has to match this regular expression this string does?
>> Speaker 1: Yes, you can do regular expressions. I'm not exactly sure how you do them on the schema but you can do them in what's called a lifecycle.
>> Speaker 1: Yeah, but I don't know the keyword. I don't know if it's regex and then you say some regex here?
[00:12:09] You know what I mean? I don't know the actual keyword here that would allow you to write that regex. I'm sure it does exist. I just haven't used it. If I were to do it, I would've do the regex like in a customer validator. So Mongoose actually has middleware just like Express does and we can set up middleware to do things before things get saved.
[00:12:30] After things get saved or before they're creating or after they get created we could do things. So before something gets saved, I might run it through a regex, make sure it does this and if not, don't save it. Yep?
>> Speaker 2: So if you had an iffy on true there, that would work, right?
>> Speaker 1: If you had a iffy on true?
>> Speaker 1: No, I'm confused. So these are keywords in Mongoose, right?
[00:13:09] It's like these are cousin validators that Mongoose has built into the schema. And by using that keyword and putting true or false, it's enabling or just disabling it.
>> Speaker 2: Yeah, I get that. I'll show it to you in a bit.
>> Speaker 1: Okay.
>> Speaker 2: And you can give me your what your thoughts are.
>> Speaker 1: I think exactly what you want is exactly what I was saying. It's middleware.
>> Speaker 2: Okay.
>> Speaker 1: Because at this time, right now, there is no value, it's just a type. You won't know the values until somebody tries to save it. And at that time, we're going to check to make sure that it follows this regex before it's saved.
[00:13:41] That's middleware.
>> Speaker 2: Yeah, gotcha, okay.
>> Speaker 1: Yeah, that is- We'll get into that when we start doing authentication probably.