Instructor: Let's now use a process called populate
in order to actually get access to the referenced
tour guides whenever we query for a certain tour.
So, in the last video, we created a reference
to the user, here in this guides field,
right in our tour model, right?
And now we're gonna use populate in order to
basically replace the fields that we referenced
with the actual related data.
And the result of that will look as
if the data has always been embedded,
when in fact, as we know, it is in
a completely different collection okay?
Now, the populate process always happens in a query.
And so let's now go to our tour controller,
and then right to the function where we get a single tour.
So here, in get tour.
And here's our query, right?
So this here, is where we build our query.
And now all we need to do is to add
the populate to the query.
So populate, and then the name of the field
which we actually want to populate
and that is called guides, okay?
And if you think about it, this name actually makes sense.
So we want to populate so basically to fill up
the field called guides in our model.
Right, so again, this guides field
only contains the reference.
and with populate we're then gonna fill it up
with the actual data, all right and again only in the query
and not in the actual database, okay?
So, this is really all we need to do.
And let's now take a look at the result, okay?
So, this is the id of the tour and let's remember
that this is how the guides look right, right now, okay?
But if we now, get tour and with that id,
then let's now wait for it,
and indeed, here is the data about the guides.
Okay, so these two elements that we had in the guides
already, have now been populated with the actual data.
And if we now take a look at get all tours,
let's actually get rid of some of this stuff here.
We have too much stuff open here.
So if we now get all the tours,
okay, then let's scroll to the end
where the new one should be
and apparently it's now well,
oh that's because I have this filter here,
let's get rid of that, and now I have my 10 results
and actually it's right here, so the new test tour.
And now you see that in here it's back to showing us
only the values that are actually in the database.
So let's also confirm that here in Compass.
And so indeed, as you see, we still do not have the actual
data in here in the database, but only really the ids.
Okay, and it's only that populate step which will then
replace these ids with the actual data, okay?
And so right here, that doesn't happen
well because, we didn't implement the populate
in the get all tours route handler.
Okay, now let me just show you a small trick
that we can do with the populate function.
Which is to actually also just select the certain fields.
So for example, we're not interested in this v property here
and also not in passwordChangedAt right,
so that's not the kind of data
that we want about our tour guides.
And so here in populate, we can actually specify that.
So instead of just passing in the string,
we can create an object of options
and then we can say,
the path is guides, so basically, the name of the field
we want to replace, and then, as usual, we can use select,
and then minus,
this one here and also, the other one,
so passwordChangedAt, it's just easier to copy,
all right, so let's change it here,
and send this again.
And this is of course, not the right route,
so sorry for that, I think I also used it before actually
where really I wanted to show you this one,
right, and so sorry for that, but still
what we want to get rid of here is this V
and this passwordChangedAt.
And so we already did that,
so if we send it now, then of course
we only get the data that we're interested in.
All right, so this populate function
is an absolutely fundamental tool
for working with data in Mongoose.
And especially of course when there
are relationships between data,
okay, so you should always know exactly how and when
to use it for your own applications.
And in order to train for that, we will of course use it
many times more throughout this section.
Now just one thing that I want you to keep in mind,
is that behind the scenes, using populate will still
actually create a new query,
and so this might affect your performance.
Okay, of course if you only do it once or twice
and in a kind of small application, then that small
hit on performance is no big deal at all.
But in a huge application, with tons of populates
all over the place, then that might indeed
have some kind of effect, okay?
So just keep that in mind.
Okay, and really it makes sense, right
because how else would Mongoose be able to get data
about tours and users at the same time.
It needs to create a new query basically in order to
be able to create this connection.
Okay and now just to finish this,
let's remember what I showed you that
this actually didn't work when we get all the tours.
So, remember how in this situation,
we still simply get the ids of the tour guides
and not the referenced user data.
Okay, and so one solution would basically
be to copy this code here, so this populate function,
also here into this route handler,
but of course, duplicate code is never a good idea.
And I hope that you already know
at this point of a better way of doing this.
And the answer to that is query middleware.
Okay, so let's quickly go ahead and move to our model,
and I'm copying this code here now
and so, yeah let's do that right here.
So,
a pre and then I will actually just as before
do it with a regular expression, which is then gonna work
for everything that starts with find.
So, just like this,
Okay, and of course, we do this in query middleware,
well because, this is the kind of middleware
that is going to run each time there is a query.
Right, let's just put all of these pre middlewares together
and then after that have the post one.
All right, so let me copy the code that we had before
and now let's just add it to this,
because remember that in query middleware,
this always points to the current query.
And so now basically all of the queries will then
automatically populate the guides field
with the referenced user.
Okay, and so we can now get rid of it here.
And yeah, that's actually it.
So now we do it here, instead of doing it
in two places, in the controller.
And so this is a nice little trick in case that you always
want to populate all your documents.
So, let's test it out.
First, if it still works here.
And indeed it does, so we get our two users.
And then let's test it here where it didn't work before
and now it does, so here's the result of that.
And now just to make sure that it does actually work,
let's also update it and basically add another tour guide.
So let's copy the id of the tour here then update tour
so we need to put the id here,
and then in the body let's get it from create tour,
so this guides,
and put that here, and then we also
need to get our other user.
So, it's this one here, which is actually not a guide
or not even an admin, but still this is just for testing,
and so let's grab this id,
and then go ahead and put it here.
So, let's update it, that still works,
and so now actually, even in this output,
we already have the populated data.
Okay, because in our regular expression
remember we used find.
And so, this updating here is implemented using find
by id and update, and so it also starts with find
and so therefore the query middleware that we were before
also applies to this function.
Okay and so, this is how populating works.
Okay, so again, extremely important tool
in your Mongoose toolbox, all right.
And just to make sure, let's take
15 seconds here to recap.
So this is a two step process.
First, you create a reference to another model.
And so, with this, you effectively create
the relationship between these two datasets.
Then, in the second step, you populate that field
that you just specified before,
so guides using the populate method.
All right, so very simple, very straightforward,
all you need is to really understand
the logic behind all of this and then
you're ready to actually start using it.