Check out a free preview of the full API Design in Node.js (using Express & Mongo) course:
The "ObjectId" Lesson is part of the full, API Design in Node.js (using Express & Mongo) course featured in this preview video. Here's what you'd learn in this lesson:

The ObjectId type is used to create primary/foreign key relationships between objects in the database. While this property looks like a String, it’s actually an Object with a unique reference. Scott explains how to use the ObjectId type and answers a number of audience questions about it.

Get Unlimited Access Now

Transcript from the "ObjectId" Lesson

[00:00:00]
>> [MUSIC]

[00:00:03]
>> Speaker 1: And here's the interesting part, as far as relationships go. If you're a SQL person, a relational database person, you're probably like yeah, it's not really relations. But this is how it works in Mongoose. What we can do is if we wanna set a relationship between two models, we can just associate the ID, just like you would in any other database, it's just how it works.

[00:00:27] So in Mongoose, the way it works is, we give it the type of ObjectId. ObjectId is IDs, they are IDs in Mongoose, they're just called ObjectIds. So if we say yeah, we want the dog to have one owner. So it's type is Mongoose.Schema.Types.ObjectId and that's means, it looks like a string of an ID when you get it back from the database but it's not, it's actually an object that converts it to a string.

[00:00:56] I want to reference the owner schema. So there exists in this database somewhere another model called owner. So if there's a string here, I'm telling Mongoose that that ID is referencing some owner somewhere, and then it's required. So you can't save a dog without an owner. The reason that exists, and we'll get to it later, is something called population.

[00:01:19] And population is like, you can say it's almost like creating a join at call time. So that doesn't exist the join table and the database like you would have something with SQL. But when we want to see who the owner is we can ask mongoose about it and it'll join it for us when we ask for it.

[00:01:37] But it will not persist in the database. It's not atomic.
>> Speaker 1: So we'll get to that later, but that's how you set up relationships. So a lot of people I've talked to who bash on mongo and mongoose and you can't do relations, there's no such thing like. Yeah you can, you could totally do relations, one to one, many to many, whatever you want.

[00:02:00] One-to-many? So any questions about that? Yes.
>> Speaker 2: They want you to clarify the difference between collection, model, and schema.
>> Speaker 1: Yeah, I guess, that's a good question, I've been using them kinda loosely. So let's go back to the dbTester. So a schema is the actual blueprint, this is how I want my data to look, so blueprint for the data.

[00:02:30] The model is the JavaScript representation that we're gonna be using inside of our API to access the document which is in the database. The document is the instance that belongs to the collection. So you can think of the model and the document as the same thing, except for the model is like what we're using in JavaScript, and the document is what exists in the database, that's part of an entire collection.

[00:02:57] So a collection is just a group of these documents, and a model is our JavaScript representation. And the schema is the blueprint that defines the model and the document.
>> Speaker 1: Any other questions? Yep.
>> Speaker 2: Can you explain the ObjectId type?
>> Speaker 1: Yeah so, ObjectId type. It'll make more sense when you actually see it.

[00:03:30] But when you see it you'll be like, it's just a string. But it's actually no, I could just show you. We made some stuff already. So, the ObjectId type is, I'll just open up Robomongo cuz it's there, it's easier.
>> Speaker 1: So, we'll go look in puppies > Collections > Let's go look in todos.

[00:03:57]
>> Speaker 1: So right here. So in Mongo everything that gets saved in the database, every document, gets an underscore id property, and that value is an ObjectID. As you can see right here, it says ObjectID. That's what an ObjectID is. That's what Mongo or Mongoose describes as a object ID.

[00:04:16] But when you retrieve it from the database, and your using a JavaScript, it's just going to be this string right here. It's gonna be a string that's in actual quotes. But it's actually an object, but they convert it to a string so we can consume it in JavaScript a lot easier.

[00:04:32] It's just called ObjectId, just think of it as a string though. Whenever you use it inside of the ORM, it's gonna be a string.
>> Speaker 1: You can do equality checks on it just like a string
>> Speaker 1: But it's just good to know that it is an object in the database, it's ObjectID.

[00:04:55]
>> Speaker 2: Scott?
>> Speaker 1: Yes.
>> Speaker 2: I know this is just a training example, but how would the dog schema know what owner it is?
>> Speaker 1: Right, so it doesn't. So what will happen is when you create the dog you'd have to, so that's a good question. So if we go back here, when we were to say, I wanna make a new dog, all right.

[00:05:14] I'm gonna pass on all these properties on an object, and then we get to the owner property, you need to pass in the owner's ID right there, that's how it would know. So if you were to look this up in the database, if you were to look this dog up in the Robomongo and when you got down to the owner property, its value would be one of these, it'd be an ObjectId.

[00:05:37]
>> Speaker 1: So yeah you have to tell it, you have to save that dog with the owner's ID. And hopefully the owner is the person that made a post request to the server so hopefully you have the ID. If not then you just won't be able to save it cuz it's required.

[00:05:52]
>> Speaker 1: Cool, any other questions?
>> Speaker 3: Is it faster to do finds on an ObjectId versus on a property in the schema?
>> Speaker 1: Yeah, good question. So ObjectId is indexed by default. They are indexed, so if you want to do a find on some other property, it won't be as fast as the ObjectId's because they're indexed.

[00:06:13] So they can get to them a lot faster than having to do some search across a collection or the entire database on let me find all the puppies with this name. Yeah, it'll come back relatively fast, but not as fast if you're like find the puppy with this ID.

[00:06:29] It's constant time, it's gonna go straight to that ID and be there you are. All right, it's indexed where as everything else is not by default. But you can index whatever you want using Mongoose. You know what? I want to index the names too cuz you know what?

[00:06:43] They're unique, let's index these. You can do that too. You can totally do that. But by default, IDs are indexed.
>> Speaker 1: Yep?
>> Speaker 2: Is there a max length on ObjectId?
>> Speaker 1: You don't create the ObjectId. The ObjectId is created for you when you save it so you never have to worry about generating an ID which would be not fun at all.

[00:07:09] I mean that would be really, that's a whole other thing, managing ID's. You don't have to worry about that, it's created for you. You put an object in a database, when it comes out there's an ID. Just like the stuff that we've been doing this whole time, right?

[00:07:21] If we go look at at the Mongo shell.
>> Speaker 1: And we go to our database, and we say db.todos.find. Here's an ObjectId on this todos things. We didn't add that anywhere. We didn't add that ObjectId, right? If we go look in the file, not once did I have a property on it that said ObjectId, I didn't put that there.

[00:07:48]
>> Speaker 1: When I saved it did. It also added this version and all this other stuff here.
>> Speaker 1: So underscore ID is the property. So also remember that, it's underscore ID. So it would be todos._id, not todos.id. If you're not used to it, so it's gonna be _id. That's the ID property.

[00:08:10] Any other questions?
>> Speaker 2: How would you go about creating an index?
>> Speaker 1: That's a little more advanced and we'll get into that. I don't wanna get into something that we don't need right now. But yeah, it's not that hard, there's a couple ways you can do it, that's why I don't wanna get into it.

[00:08:28] There's three ways.
>> Speaker 2: And then I think there was a question on, so if you're creating users in your database, would you actually make a fieldscalled ID or would you just use the built in underscore id field?
>> Speaker 1: I would use the built-in underscore ID field as an ID for every single model in my database, but that doesn't mean you won't have something else unique about, let's say a user.

[00:08:55] So let's say a user logs into your app with Facebook, right? Facebook generates a unique token, or unique ID. Maybe you wanna use that. You can also use that if you want to, but it doesn't mean you shouldn't use the ObjectId, I would use the ObjectId. But if you wanted to create your own, I guess you could.

[00:09:13] You could totally do that. But then again, you'll be managing your own IDs, and indexing them and stuff like that. But there are times where you might wanna use your own. But I would always just use the ObjectIds.
>> Speaker 2: So there's a question, since we're running mongoose in the application, this does nothing to stop us from interacting with the database elsewhere and screwing up the schema, is that correct?

[00:09:41]
>> Speaker 1: That's exactly correct. So if we had a Schema in our JavaScript like, todos must look like this. If we made a todo with Mongoose, we couldn't save a todo without following this blueprint. We couldn't just, I wanna make a new todo and put something else here, right?

[00:10:03] That thing won't get saved cuz it's not part of this schema.
>> Speaker 2: But the other stuff will.
>> Speaker 1: Yeah, but if I go into the shell or in Robomongo, it doesn't care about the schema. It'll just like, yeah, just write to it. So yeah, remember that's what I'm saying.

[00:10:18] Mongo doesn't care about what you give it. It's mongoose that's doing that validation and blueprinting with the schemas. So yeah, you gotta remember that. I've actually ran into times where that has come to burn me if you have a service or architecture where you have these three services that are target to the same database.

[00:10:35] This service is using the same model as this service, right? So how do you keep those things in sync? Do you write the same schema twice on both, it's kind of hard. So yeah, I've ran into the problem before, and it sucks. Any other questions?
>> Speaker 2: Does Mongo throw an error if the data does not match the schema?

[00:10:58]
>> Speaker 1: It depends, if it's a validation, if it doesn't match a required or a unique, or something like that, it will throw an error. But if you just add something that you didn't blueprint, it won't throw an error, it just won't save that thing.