‫In this video, we're gonna use
‫a simple trick in order to prevent users
‫from writing multiple reviews for the same tours,
‫so basically preventing duplicate reviews.
‫So in the last video, we created all these reviews
‫in order to calculate the averages.
‫And we created multiple reviews for one tour,
‫but all from the same user.
‫But in practice, that doesn't make much sense, right?
‫So in the real world, each user
‫should only review each tour once.
‫So basically, a duplicate review happens
‫when there is a review with the same user
‫and the same tour ID.
‫And that's what we want to avoid from happening.
‫And the obvious solution here is
‫to just use a unique index, right?
‫However, it is not enough to set
‫both these fields to unique.
‫And actually that would really be very wrong,
‫because that would mean that each tour can get only review,
‫and each user can only write one review.
‫And obviously that's not what we want.
‫So what we do need is them both together to be unique,
‫so the combination of user and tour to be always unique.
‫So that sounds a bit complicated, but luckily for us,
‫that's actually very easy to achieve with indexes.
‫So we already created a compound index on the tour before,
‫and so now let's do the same here on the reviews.
‫So again, right here after the schema definition,
‫and of course we're still in the review model, right?
‫So review, and that's not correct,
‫so review schema dot index...
‫Tour set to one, and once more it's not really important
‫if it's one or minus one in this case.
‫And user also set to one, okay.
‫And so again, that's similar to what we did before,
‫but here we're going to take it to the next level
‫and now add an object for options.
‫And the option here that we're gonna set is unique
‫(typing)
‫set to true.
‫And that's actually it.
‫This will achieve exactly what we want.
‫So now each combination of tour and user
‫has always to be unique.
‫So let's give it a save here, or two,
‫and then go test this out actually.
‫Now when I first tested this,
‫it actually didn't work right away.
‫Really, it only just started working the next day,
‫and I'm not really sure why, but if that happens to you,
‫then don't worry about that, okay.
‫And maybe it might even happen now
‫as I'm recording this video.
‫So anyway, right now, there should not be any reviews
‫on the tour that we were working on.
‫So just to make sure we still have zero ratings
‫and also the reviews are empty.
‫And so let's now once more create
‫a new review on this tour.
‫Okay.
‫So this is one review, so one user and one review.
‫So that of course should work, but if I now send this again
‫and let's say I set it to four and say okay,
‫then this should not be allowed to work, okay.
‫Just keep in mind that it might still work
‫because of the issue I was telling you before, okay.
‫So sometimes this kind of index doesn't get set immediately.
‫Oh, but actually, in my case here it worked right away.
‫So we get this duplicate key error on this index here,
‫and so that's exactly the index that we just created before.
‫So let's take a look at that also here in Compass.
‫So here it actually is not,
‫and so I will do it just like I did before
‫and reconnect basically.
‫So going to the recents, then connecting here.
‫Natours...
‫Then...
‫Of course the tours,
‫and our indexes here are now these four.
‫And so that's the one that we just created,
‫or actually it's not (laughs), okay.
‫So for some reason, it's not here,
‫so that's just what I was saying earlier,
‫but don't mind because actually it is working in our code.
‫Okay, so we were not able to create two reviews
‫coming from the same user, okay.
‫But if you now log in as someone else,
‫well, then we will certainly be able to post this review.
‫So let's see what user we could use now.
‫So let's get all users here,
‫which I can't because I'm not an admin (laughs), okay.
‫So I forgot about that part,
‫and so I'm simply going to retrieve this from Compass.
‫Sometimes that's just easier.
‫So this is a guide, a user (exclaims),
‫so let's just use this Eduardo here or something.
‫So let's log in as this person, as this user.
‫Yep, with success, and now we should be allowed
‫to create a review, and indeed here it is, okay.
‫And if we now update this,
‫then we have our two ratings, great.
‫Now just testing it again, so if we send it again,
‫it's not going to work because again,
‫we have a duplicate error.
‫Awesome.
‫There is just one more thing that I wanted to show you,
‫and so for that, I'm going to log in as yet another person,
‫okay, so that I can then create another review.
‫So this time, I'm gonna be this Max Smith.
‫And so let's log in.
‫(mouse clicks)
‫Okay, so now I'm officially Max,
‫and I will be able to post this review.
‫So with five,
‫I'm able to do that,
‫and now I want to take a look at the average.
‫Okay, so right now it is this 4.6666,
‫which of course does not look good.
‫And we could fix this in the front end.
‫For example when we request this data
‫from the API and then display it,
‫we could on the front end then do this rounding.
‫But actually, I want to do it right here on the back end
‫so that the end user already gets this final rounded value,
‫which in this case would be 4.7, right?
‫And for doing that, I'm gonna show you a small new feature
‫in Mongoose that we didn't use yet.
‫So let's go to our tour model,
‫and to that average,
‫so right here.
‫And so now, we can use a setter function.
‫(typing)
‫So set and this function will be run each time
‫that a new value is set for this field, okay.
‫And so here, we usually specify a callback function,
‫which receives the current value.
‫And in this case, it returns basically this value,
‫but rounded.
‫So we use math dot round for the current value,
‫but the problem with math dot round is that
‫it rounds values to integers.
‫So for example, if we had something like this,
‫it would then round this to five, okay.
‫And that's not what we want.
‫We want it to be rounded to 4.7.
‫And so we're gonna use a trick here,
‫which is quite common, so multiplying this by 10,
‫and so with that, we would get 46.666,
‫and then this rounded would be 47.
‫And so then, we divide the results by 10 again,
‫and that then is 4.7.
‫All right, and that's actually it.
‫So again, a setter function here which is going
‫to be run each time that there is a new value
‫for the ratings average field.
‫So just to test this, let's actually simply
‫update this last review that we added,
‫which had a five, and let's keep it at five.
‫So all we basically want to do is to re-run
‫that function which creates this average.
‫So if I do this now and now get my tour,
‫we should get 4.7 here as the average.
‫And yep, here we go.
‫Great, and that's actually it already for this video.
‫So we created this nice setter function,
‫and we created this unique compound index here
‫in order to ensure that one user
‫cannot write multiple reviews for the same tour.