1 00:00:01,060 --> 00:00:03,880 Welcome back to the next video. 2 00:00:03,880 --> 00:00:05,834 And let's keep it going now with a new 3 00:00:05,834 --> 00:00:08,409 and pretty advanced Mongoose feature 4 00:00:08,409 --> 00:00:10,917 called 'Virtual Populate.' 5 00:00:12,410 --> 00:00:14,441 So, at the point, we have populated 6 00:00:14,441 --> 00:00:16,220 the reviews with the tour and 7 00:00:16,220 --> 00:00:20,940 the user data right here, right? 8 00:00:20,940 --> 00:00:22,516 And so, right now, when we query for reviews, 9 00:00:22,516 --> 00:00:26,160 we get access to that information. 10 00:00:26,160 --> 00:00:29,086 However, that still leaves one problem unsolved. 11 00:00:29,086 --> 00:00:33,290 So, how are we going to access reviews on the tours? 12 00:00:33,290 --> 00:00:34,936 So basically, the other way around. 13 00:00:34,936 --> 00:00:38,380 So, let's say that I queried for a specific tour. 14 00:00:38,380 --> 00:00:39,766 And then, how will I get access 15 00:00:39,766 --> 00:00:42,306 to all the reviews for that tour? 16 00:00:42,306 --> 00:00:44,803 And this problem arises here because 17 00:00:44,803 --> 00:00:47,357 we did parent referencing on the reviews. 18 00:00:47,357 --> 00:00:50,676 So basically, having the reviews pointing to the tours 19 00:00:50,676 --> 00:00:54,350 and not the tours pointing to the reviews. 20 00:00:54,350 --> 00:00:57,180 And so, as we said in the beginning of the section, 21 00:00:57,180 --> 00:00:58,660 in this case, the parent does not 22 00:00:58,660 --> 00:01:01,560 really know about its children. 23 00:01:01,560 --> 00:01:03,060 And so, in this example, 24 00:01:03,060 --> 00:01:06,480 the tour does not know about its reviews. 25 00:01:06,480 --> 00:01:08,170 And sometimes, that's okay. 26 00:01:08,170 --> 00:01:10,750 But in this case, we actually want the tour 27 00:01:10,750 --> 00:01:14,790 to basically know about all the reviews that it's got. 28 00:01:14,790 --> 00:01:16,470 Now, in order to solve this, 29 00:01:16,470 --> 00:01:18,110 with what we know at this point, 30 00:01:18,110 --> 00:01:20,330 we could have two solutions. 31 00:01:20,330 --> 00:01:23,050 And the first one would be to manually query 32 00:01:23,050 --> 00:01:26,570 for reviews each time that we query for tours. 33 00:01:26,570 --> 00:01:28,106 But it would be a bit cumbersome 34 00:01:28,106 --> 00:01:30,550 doing it manually like this. 35 00:01:30,550 --> 00:01:33,440 And the second solution could be to also 36 00:01:33,440 --> 00:01:35,860 do child referencing on the tours. 37 00:01:35,860 --> 00:01:37,810 So basically, keep an array of all 38 00:01:37,810 --> 00:01:40,460 the review ID's on each tour document. 39 00:01:40,460 --> 00:01:42,100 Then, all we would have to do 40 00:01:42,100 --> 00:01:45,020 is to populate that array, right? 41 00:01:45,020 --> 00:01:47,513 But, we actually already ruled out doing this 42 00:01:47,513 --> 00:01:49,341 right in the beginning because 43 00:01:49,341 --> 00:01:51,751 we do not want to store that array 44 00:01:51,751 --> 00:01:53,785 of review ID's that could then grow 45 00:01:53,785 --> 00:01:57,190 indefinitely in our database, right? 46 00:01:57,190 --> 00:01:59,770 And that's actually exactly why we picked 47 00:01:59,770 --> 00:02:02,243 parent referencing in the first place. 48 00:02:02,243 --> 00:02:05,450 However, there is great solution for this. 49 00:02:05,450 --> 00:02:08,040 And that's because Mongoose actually offers us 50 00:02:08,040 --> 00:02:10,054 a very nice solution for this problem 51 00:02:10,054 --> 00:02:14,930 with a pretty advanced feature called 'Virtual Populate.' 52 00:02:14,930 --> 00:02:16,809 So with 'Virtual Populate,' we can actually 53 00:02:16,809 --> 00:02:20,020 populate the tour with reviews. 54 00:02:20,020 --> 00:02:21,503 So, in other words, we can get access 55 00:02:21,503 --> 00:02:24,624 to all the reviews for a certain tour, 56 00:02:24,624 --> 00:02:29,624 but without keeping this array of ID's on the tour. 57 00:02:29,850 --> 00:02:31,535 So, think of 'Virtual Populate' like a way 58 00:02:31,535 --> 00:02:35,316 of keeping that array of review ID's on a tour, 59 00:02:35,316 --> 00:02:39,750 but without actually persisting it to the database. 60 00:02:39,750 --> 00:02:41,916 And so that then solves the problem that we have 61 00:02:41,916 --> 00:02:44,790 with child referencing, right? 62 00:02:44,790 --> 00:02:49,490 So, it's a bit like virtual fields, but with populate, okay? 63 00:02:49,490 --> 00:02:51,030 So, just to illustrate that, 64 00:02:51,030 --> 00:02:54,030 let's go to our tour model here. 65 00:02:54,030 --> 00:02:56,430 And so, what I just described would be, 66 00:02:56,430 --> 00:02:59,310 in theory, to do something like this. 67 00:02:59,310 --> 00:03:00,670 So, on our tour model, 68 00:03:00,670 --> 00:03:03,447 we would add a field called 'Reviews.' 69 00:03:03,447 --> 00:03:06,114 (keys clicking) 70 00:03:07,050 --> 00:03:11,371 And then set the type to Mongoose.Schema.ObjectId. 71 00:03:11,371 --> 00:03:13,782 (keys clicking) 72 00:03:13,782 --> 00:03:15,910 And you don't need to write this. 73 00:03:15,910 --> 00:03:18,629 I'm just doing it to show it to you. 74 00:03:18,629 --> 00:03:20,920 (keys clicking) 75 00:03:20,920 --> 00:03:24,710 And then connect it with 'Review.' 76 00:03:24,710 --> 00:03:28,683 And of course, this here would have to be an object. 77 00:03:28,683 --> 00:03:31,763 But, what matters here is that this is basically 78 00:03:31,763 --> 00:03:35,100 how we would implement child referencing. 79 00:03:35,100 --> 00:03:38,150 So the tour referencing reviews, okay? 80 00:03:38,150 --> 00:03:40,174 But again, we do not want to do it. 81 00:03:40,174 --> 00:03:43,848 So instead, we're going to implement 'Virtual Populate.' 82 00:03:43,848 --> 00:03:45,980 (keys clicking) 83 00:03:45,980 --> 00:03:48,480 All right. And it works like this. 84 00:03:48,480 --> 00:03:52,337 So we do it here on the tour schema. 85 00:03:52,337 --> 00:03:54,470 (keys clicking) 86 00:03:54,470 --> 00:03:57,000 And we still do it .virtual. 87 00:03:57,000 --> 00:04:00,283 So just like with this virtual field here, duration week, 88 00:04:00,283 --> 00:04:04,158 then we type in the name of the virtual field. 89 00:04:04,158 --> 00:04:05,936 So let's call it 'Reviews,' 90 00:04:05,936 --> 00:04:10,450 and then an object of some options. 91 00:04:10,450 --> 00:04:12,017 And the first one is the name of the model 92 00:04:12,017 --> 00:04:14,030 that we want to reference. 93 00:04:14,030 --> 00:04:16,850 And so that works just like with the normal referencing. 94 00:04:16,850 --> 00:04:18,920 (keys clicking) 95 00:04:18,920 --> 00:04:21,360 So again, the name of the model. 96 00:04:21,360 --> 00:04:23,580 So, 'Review' or course, in this case. 97 00:04:23,580 --> 00:04:26,490 And now, we actually need to specify the name of the fields 98 00:04:26,490 --> 00:04:29,320 in order to connect the two data sets. 99 00:04:29,320 --> 00:04:31,570 And this is, for me, the most complicated part 100 00:04:31,570 --> 00:04:33,810 of implementing this 'Virtual Populate.' 101 00:04:33,810 --> 00:04:37,420 And so, let's make sure you really understand this part. 102 00:04:37,420 --> 00:04:39,880 So here, we need to specify two fields. 103 00:04:39,880 --> 00:04:42,166 The foreign field and the local field. 104 00:04:42,166 --> 00:04:46,940 So let us start with the foreign field. 105 00:04:46,940 --> 00:04:49,990 And so, this is the name of the field in the other model. 106 00:04:49,990 --> 00:04:51,636 So in the Review model in this case, 107 00:04:51,636 --> 00:04:54,940 where the reference to the current model is stored. 108 00:04:54,940 --> 00:04:59,050 And that is, in this case, the Tour field, right? 109 00:04:59,050 --> 00:05:00,396 So, let's take look at that. 110 00:05:00,396 --> 00:05:02,867 And so, again, in our review model, 111 00:05:02,867 --> 00:05:05,490 we have a field called 'Tour.' 112 00:05:05,490 --> 00:05:08,940 And so this is where the ID of the tour is being stored. 113 00:05:08,940 --> 00:05:11,442 And so that's why here, in this foreign field, 114 00:05:11,442 --> 00:05:14,111 we specify that name of that field 115 00:05:14,111 --> 00:05:17,720 in order to connect these two models, okay? 116 00:05:17,720 --> 00:05:20,220 And now we need to do the same for the current model. 117 00:05:20,220 --> 00:05:23,060 So, we need to say where that ID is actually stored 118 00:05:23,060 --> 00:05:25,773 here in this current Tour model. 119 00:05:26,720 --> 00:05:27,883 So, local field. 120 00:05:29,520 --> 00:05:32,090 And that is, the ID. 121 00:05:32,090 --> 00:05:34,600 So, _ID, okay? 122 00:05:34,600 --> 00:05:37,368 And so, again, this _ID, which is how 123 00:05:37,368 --> 00:05:39,285 it's called in the local model, 124 00:05:39,285 --> 00:05:42,400 is called 'Tour' in the foreign model. 125 00:05:42,400 --> 00:05:45,070 So, in the Review model. Okay? 126 00:05:45,070 --> 00:05:47,020 And so again, this is how we connect 127 00:05:47,020 --> 00:05:48,763 these two models together. 128 00:05:49,690 --> 00:05:51,750 Let's us write here that this is 129 00:05:51,750 --> 00:05:55,223 'Virtual Populate,' okay? 130 00:05:56,230 --> 00:05:58,580 And so now, with this setup, we can actually use 131 00:05:58,580 --> 00:06:01,260 Populate just like we did before. 132 00:06:01,260 --> 00:06:03,370 And so what we want to do now is to go ahead 133 00:06:03,370 --> 00:06:05,475 and populate the tour when we only 134 00:06:05,475 --> 00:06:08,860 get one single tour, okay? 135 00:06:08,860 --> 00:06:13,860 So here in Postman, it is in this situation of 'Get Tour.' 136 00:06:14,130 --> 00:06:16,830 Okay? Let's see of this actually exists. 137 00:06:16,830 --> 00:06:19,963 And it does, but it's this weird test tour. 138 00:06:21,490 --> 00:06:25,933 And so, let's actually do it with this 'Forest Hiker' one. 139 00:06:29,101 --> 00:06:30,033 All right. 140 00:06:32,380 --> 00:06:33,980 So, when we get this tour, 141 00:06:33,980 --> 00:06:36,080 we now want to populate the reviews. 142 00:06:36,080 --> 00:06:39,073 And it should already be here as an empty array. 143 00:06:39,980 --> 00:06:41,220 Ah, here it is. 144 00:06:41,220 --> 00:06:43,810 It's not an empty array, but it's set to 'null.' 145 00:06:43,810 --> 00:06:45,540 But the virtual field is actually 146 00:06:45,540 --> 00:06:47,450 already there with the reviews. 147 00:06:47,450 --> 00:06:49,160 But it's null at this point because 148 00:06:49,160 --> 00:06:51,830 we didn't yet populate it, okay? 149 00:06:51,830 --> 00:06:53,800 And again, we only want to populate it 150 00:06:53,800 --> 00:06:54,940 here in the 'Get One Tour,' and not 151 00:06:54,940 --> 00:06:57,360 in the 'Get All Tours' because that 152 00:06:57,360 --> 00:06:59,319 would be a bit too much information to send 153 00:06:59,319 --> 00:07:03,250 down to a client when they get all the tours. 154 00:07:03,250 --> 00:07:05,350 Also, when we're getting all the tours, 155 00:07:05,350 --> 00:07:08,030 that's usually to build an overview page. 156 00:07:08,030 --> 00:07:09,340 And in that case, we usually 157 00:07:09,340 --> 00:07:12,000 do not need access to all the reviews. 158 00:07:12,000 --> 00:07:13,440 We only need that when we are 159 00:07:13,440 --> 00:07:15,600 really displaying just one tour. 160 00:07:15,600 --> 00:07:17,080 Okay? And so, I think it makes sense 161 00:07:17,080 --> 00:07:20,117 to only do this populate on 'Get One Tour.' 162 00:07:21,060 --> 00:07:23,010 So, let's do that populate actually 163 00:07:23,010 --> 00:07:24,803 right in the controller. 164 00:07:24,803 --> 00:07:27,543 So, the tour controller and down here 165 00:07:27,543 --> 00:07:31,010 where we have 'Get Tour.' 166 00:07:31,010 --> 00:07:33,473 And so, that's actually very easy. 167 00:07:33,473 --> 00:07:36,624 Only to do is to call 'Populate' after the other query, 168 00:07:36,624 --> 00:07:40,670 and then simply pass the name 169 00:07:40,670 --> 00:07:42,850 of the field that we want to populate. 170 00:07:42,850 --> 00:07:45,803 And so, as we already know, that is called 'Reviews.' 171 00:07:45,803 --> 00:07:48,613 And, so that should actually be it already. 172 00:07:50,520 --> 00:07:51,460 All right? 173 00:07:51,460 --> 00:07:54,573 So, let's test this now, and take a look at this. 174 00:07:57,500 --> 00:08:02,010 And indeed, we now get our complete review right here. 175 00:08:02,010 --> 00:08:04,570 All right? So that got populated. 176 00:08:04,570 --> 00:08:07,160 And so it means that our Virtual Populate 177 00:08:07,160 --> 00:08:09,130 is actually working. 178 00:08:09,130 --> 00:08:10,913 Now, you might start to see that 179 00:08:10,913 --> 00:08:12,752 this is creating kind of a problem 180 00:08:12,752 --> 00:08:15,166 because this here is basically creating 181 00:08:15,166 --> 00:08:17,410 a chain of populates. 182 00:08:17,410 --> 00:08:19,400 And that's not ideal at all. 183 00:08:19,400 --> 00:08:22,690 So, we have the tour being populated with reviews. 184 00:08:22,690 --> 00:08:24,950 But then the reviews also get populated 185 00:08:24,950 --> 00:08:28,100 with the tour again, and also with the user. 186 00:08:28,100 --> 00:08:30,280 And then also the tour is also 187 00:08:30,280 --> 00:08:32,270 getting populated with guides. 188 00:08:32,270 --> 00:08:34,160 Which in this case, is not happening 189 00:08:34,160 --> 00:08:35,820 because there are no guides. 190 00:08:35,820 --> 00:08:38,770 But if there were, then we would have yet another populate. 191 00:08:38,770 --> 00:08:41,618 And so here we would have a chain of three populates. 192 00:08:41,618 --> 00:08:45,360 And so for performance, that's of course, not ideal at all. 193 00:08:45,360 --> 00:08:47,500 Especially here with the tour. 194 00:08:47,500 --> 00:08:49,860 So we have the tour populated with reviews. 195 00:08:49,860 --> 00:08:52,660 And in the reviews, we again have the data about the tour. 196 00:08:52,660 --> 00:08:55,550 And so that doesn't make much sense at all. 197 00:08:55,550 --> 00:08:57,430 So, it's kind of a mess now. 198 00:08:57,430 --> 00:08:59,830 SO, the solution that I'm going to use here 199 00:08:59,830 --> 00:09:01,408 is to actually turn off populating 200 00:09:01,408 --> 00:09:04,710 the reviews with the tours, okay? 201 00:09:04,710 --> 00:09:09,460 So basically, we do not need this data here on each review. 202 00:09:09,460 --> 00:09:11,950 So in this case, I think that's a good solution. 203 00:09:11,950 --> 00:09:14,370 But of course, again in your case, 204 00:09:14,370 --> 00:09:15,920 it will always depend on how 205 00:09:15,920 --> 00:09:18,077 your application works in your specific case. 206 00:09:18,077 --> 00:09:21,140 But in this app, it's more logical to 207 00:09:21,140 --> 00:09:23,357 really have the reviews available on tours, 208 00:09:23,357 --> 00:09:25,790 and it's not that important having the tour 209 00:09:25,790 --> 00:09:28,750 available on the review, okay? 210 00:09:28,750 --> 00:09:32,010 So, let's turn that populate off basically, 211 00:09:32,010 --> 00:09:33,513 in the Review model. 212 00:09:35,620 --> 00:09:36,640 Okay? 213 00:09:36,640 --> 00:09:39,573 So, let's just comment this part out, 214 00:09:40,490 --> 00:09:41,823 copy it down here, 215 00:09:44,670 --> 00:09:48,253 and so, basically get rid of this first one. 216 00:09:50,530 --> 00:09:51,420 Now all right? 217 00:09:51,420 --> 00:09:52,620 Get ready to save. 218 00:09:52,620 --> 00:09:53,790 Let's try it again. 219 00:09:53,790 --> 00:09:57,083 And so, now we should only see the ID of the tour here. 220 00:09:59,670 --> 00:10:02,800 Okay? And indeed, that's exactly what we get. 221 00:10:02,800 --> 00:10:04,627 Okay? Now with this, of course, 222 00:10:04,627 --> 00:10:07,603 we still do parent referencing, okay? 223 00:10:07,603 --> 00:10:10,648 We still keep a reference to the tours here, 224 00:10:10,648 --> 00:10:13,100 but we simply do not populate it. 225 00:10:13,100 --> 00:10:14,920 And again, because we don't always 226 00:10:14,920 --> 00:10:16,749 need that data right here. 227 00:10:16,749 --> 00:10:20,970 All right. Let's just quickly recap what we did here. 228 00:10:20,970 --> 00:10:24,698 So, we started doing only parent referencing on the review. 229 00:10:24,698 --> 00:10:26,853 But that made it so that on the tours, 230 00:10:26,853 --> 00:10:30,360 we had no access to its corresponding reviews. 231 00:10:30,360 --> 00:10:32,350 And the easiest fix for that would be 232 00:10:32,350 --> 00:10:35,090 to also do child referencing on the tours. 233 00:10:35,090 --> 00:10:36,740 But the problem with that would be 234 00:10:36,740 --> 00:10:39,000 that we do not actually want to keep 235 00:10:39,000 --> 00:10:40,801 an array of all the child documents 236 00:10:40,801 --> 00:10:43,310 on the parent document, right? 237 00:10:43,310 --> 00:10:44,993 Because again, we don't want to allow 238 00:10:44,993 --> 00:10:47,960 arrays to grow indefinitely. 239 00:10:47,960 --> 00:10:49,050 So instead of doing that, 240 00:10:49,050 --> 00:10:52,853 we implemented virtual populates like this. 241 00:10:54,279 --> 00:10:56,100 All right? So, just like this. 242 00:10:56,100 --> 00:10:59,340 And this allows us to basically do the exact same thing. 243 00:10:59,340 --> 00:11:01,940 So, keeping a reference to all the child documents 244 00:11:01,940 --> 00:11:03,049 on the parent document, 245 00:11:03,049 --> 00:11:05,911 but without actually persisting that information 246 00:11:05,911 --> 00:11:07,970 to the database. 247 00:11:07,970 --> 00:11:11,002 And so then, after having this virtual populate set up, 248 00:11:11,002 --> 00:11:14,196 all we needed to do is to basically use 249 00:11:14,196 --> 00:11:19,090 Populate just like we did before with the real references. 250 00:11:19,090 --> 00:11:20,668 And then, finally, we also turned off 251 00:11:20,668 --> 00:11:24,108 one of the populates that we had on the review. 252 00:11:24,108 --> 00:11:26,610 So, this one here, where we populated 253 00:11:26,610 --> 00:11:29,618 the tour ID, because that was creating 254 00:11:29,618 --> 00:11:33,230 an inefficient chain of populates. 255 00:11:33,230 --> 00:11:36,470 And so that's, of course, something that we do not want. 256 00:11:36,470 --> 00:11:38,430 And so, in the end, we ended up with 257 00:11:38,430 --> 00:11:43,070 a result like this, okay? 258 00:11:43,070 --> 00:11:43,903 Great. 259 00:11:43,903 --> 00:11:45,560 So, I hope that made sense to you. 260 00:11:45,560 --> 00:11:47,086 And so with this, we actually wrap up for now 261 00:11:47,086 --> 00:11:51,200 of this part of populating, okay? 262 00:11:51,200 --> 00:11:53,692 And so now let's move on to a next topic, 263 00:11:53,692 --> 00:11:56,783 which is basically creating nested routes.