Check out a free preview of the full API Design in Node.js, v3 course:
The "Mongoose Schema Solution" Lesson is part of the full, API Design in Node.js, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Scott live codes the solution to the exercise, and fields questions from students.

Get Unlimited Access Now

Transcript from the "Mongoose Schema Solution" Lesson

[00:00:00]
>> Scott Moss: Hopefully everybody had a chance to create those fields for the item model. So I'm just gonna go ahead and walk through them. Because the tests were pretty descriptive on how to do them there's some really good examples inside the list in the user resource. So I'm gonna hop into item model here and pull up our test.

[00:00:21] Whoops, go away. So if we just run test models, I already have the name on here from when I went over it, so now we have the status line. And if we look at that, this one has a few things. It expects there to be a default. Some enum stuff here, required.

[00:00:45] And a type, which is a type of string here. So I'm gonna say status, and I'll talk about all this stuff as I'm doing it. So status field, looks like it has a type of string.
>> Scott Moss: And then it has a required validation on it which is true.

[00:01:04] So it has to be there. Then it has an enum. So enum basically, is not only is it required, but it can only be one of these things. So that's what enum is saying. So it has to be either active, complete, or past due. So that's a validation on here.

[00:01:22]
>> Scott Moss: And then it has a default value of one of the enums, which is active.
>> Scott Moss: So that should pass and satisfy that status one. Gonna run that again.
>> Scott Moss: Looks like we have two passing now, and it is for sure the status one. So that one's good.

[00:01:43] So the next one is notes, so notes is just a type of string. That's the only thing that it's looking for here, so I'll say notes, and it's a string type. And that's the only thing that it's expecting, so I'll go run this,
>> Scott Moss: And it looks like we have three passing now, so that's the notes.

[00:02:05] And then the due one is, looks like it's just expecting a date, a type of date. So if I say due: type of Dates. And I'll run this one.
>> Scott Moss: Got four passing and it is the due one. So we've got that, and now we have createdBy, so if you look at createdBy, it's got this ObjectID weird thing.

[00:02:33] What the hell is that? That's not native to JavaScript. Then it's got this ref thing, so at this point, I think this is where I would have to go look at another example to see what's going on. So if we take a look at the list model, you can see it also has the exact same created by field where it's referenced.

[00:02:49] Its type is ObjectID and it's referencing the user and it's required true. So basically, this is how you set up relationships in Mongo using Mongoose. This is saying, this field is going to use the ID from a user and it's required as true, that's what that's saying. So and the reason you put a ref here, although you don't have to, but the reason you do that is when you do what's called population in Mongo which is basically like joining tables at runtime.

[00:03:16] It'll know what collection, or in this case, or I'm sorry, in the case of like SQL or table, what table to go look up and add this ID to search for. So if the ID was 1 and you did a population, it knows to go look at the user table with the ID of 1 to find the user with that ID.

[00:03:33] That's what the reference is for, so it knows where and what table does this ID belong to. That's what ref means. You don't have to do this here. You can do this when you call the populated method on the query itself. You can say, and the model you want to reference is this one.

[00:03:46] But it's better just to put it on the schema in my opinion. But even if it wasn't a schema you can overwrite in a call to population as well. So that just means the type is mongoose.SchemaTypes. You can also do Schema.Types. They're like both the same thing. SchemaTypes.ObjectID.

[00:04:15] ObjectID is how Mongo does IDs. They're like uniquely generated strings but represented as objects. They're weird. They look like strings but they're actually objects. They're called ObjectIds. And you can go look at the algorithm for them, but they generate, they can be generated off of time, they can be generate off of another ID.

[00:04:34] They can regenerate off some value, but if you look at a mongo ID, you know it's a mongo ID by the way it looks. They all look the same. And then it says it's required. And lastly, the ref must be from the user model. And the way we know that we can put user here is that we go look at the user model.

[00:05:00] The name of the model, if you scroll down, is called user. So whatever name is here, that's the name we would ref with. So this is called person, then we would ref person. But it's called user.
>> Scott Moss: So let's run the test again.
>> Scott Moss: And that passed out, so the last one is list which is very similar to createdBy.

[00:05:30] It is expecting a type of same thing, so ObjectID. It, too, is required. And this time it references the list model. And we know it's called list, because if we go look at the model here and we scroll down, it's called list right here. Of course, if you run the test, all six pass.

[00:05:59] So the extra credit was to basically add a compound index to ensure all tasks in a list have unique names. Or if you go look at the list model, there is this listSchema.index, and basically what this is saying is, I want to set a compound index on the field for user, and in the field for name, and it must be unique.

[00:06:21] So the combination of a user ID and a name on the list must be unique. So that's basically saying this name here, when paired with a user, must be unique. So what I wanna do is do the same thing except for, I wanna do it for an item in the list.

[00:06:40] So I'll go to model here, I'll say ItemSchema.index. And I wanna say for a list, I want to make this name,
>> Scott Moss: Unique. So this is, on insert, if you try to insert an item with the name of clean room and it belonged to list one, and they tried to insert another item called clean room and it also belonged to list one, it'll error out and say you can't do that because there's already an item with the name of clean room that belongs to list one.

[00:07:20] So you have to change the list or change the name. So that's a compound index. That's a little different than putting unique on the name itself. So I just made the name itself unique, the difference is, it's now, that the name has got to be unique across the database which is probably not something you want.

[00:07:37] Because I'm sure, you might have more than one user with a different name or even a list with a different name. So that would suck. That would be really bad to do that if all the names of tasks had to be unique, because somebody else in the world came out with that name other than you.

[00:07:54]
>> Speaker 2: What do the 1s mean?
>> Scott Moss: Good question. So the 1s here just mean the sorting order. Right, cuz our index is basically, index is, I don't wanna go in too much detail, at least in Mongo, it's a file with all these values, right? And what it does, it reads those files in memory, eventually it will put them in memory.

[00:08:12] So when it goes to look for those indexes, on write it will save into that file, right? So we also look at them, it has to search those indexes to find it and then it locates it, the actual document. This one just tells us, in what order do you wanna sort these fields on the index itself?

[00:08:29] So do you wanna have it to be negative 1 or do you want it to be 1? So it's basically just sorting out the indexes. And indexing by itself is literally, I could talk about indexes for a month, and I'm not an index expert at all for sure.

[00:08:45] But yeah, it's really complex. But yeah, that's just for sorting.
>> Scott Moss: Any other questions? Yes, Mark?
>> Mark: Does ref have to be a string?
>> Scott Moss: Does which one? Ref. Yes, ref has to be a string. You can't really put anything else here, not that I know of.
>> Scott Moss: Yeah, I don't know, you literally, the only thing you can put here is the reference to the collection that you wanna reference.

[00:09:13] In this case, the collections are the names of the models that you create. So yeah, not only will it have to be a string, it will have to be a real registered model that you created at some point. So if you put something random here, it won't work.

[00:09:29]
>> Speaker 3: When I did this, I started with createdBy, as the ObjectID on schema types.
>> Scott Moss: Yes.
>> Speaker 3: And then as on to the other ones, I assume that string was also on schema types and date was also on schema types? It has it on there. Any idea what those Mongoose data types are for?

[00:09:48]
>> Scott Moss: They're just referencing this. They're just like, let's just add them here, why not? But they're just doing this internally, yeah, Mark.
>> Mark: Does the order in any of these definitions matter?
>> Scott Moss: Order and the schema definitions do not matter at all. You can put them in whatever order you want.

[00:10:05] Just put them in whatever order makes sense to you as a developer and a team will make sense for y'all, but no, it's an object so it doesn't matter. But down here on the indexes, they do matter. Whatever, I know this sounds weird cuz it's JavaScript and objects don't have order, but whatever fields you define first on this index will be, when you make a compound index, it's a pair, right, so it's an umbrella.

[00:10:28] So having an index where the list is first and then name's second is different than having an index where the name is first and the list is second. Cuz it's going to go to the list, narrow down all the possibilities, and then find the name. If it was the other way around it would go to name, narrow down all of the possibilities, and find the list.

[00:10:43] So that is the only place in this whole file where order matters. Which again, I know this sounds silly because objects don't have order in JavaScript, but Mongo uses something called BSON, which is like JSON which does have ordering. It's really complicated. So they do have ordering capabilities here.

[00:11:01] So yeah, that's the only place where ordering actually matters in this entire file.