0:00
[MUSIC]
The second part of this exercise deals with the radius GET, PUT,
POST and delete operations on subdocuments inside a document.
As we saw in the example for dishes, we saw that the comments
are included inside the dish itself as its subdocument.
In the very defined, both the comment schema and the dish schema and
then define the dish model by including the comment schema into the dish schema as
an array of comments.
And we saw in the previous exercise how the comments are enclosed inside an array
In the form of a document array inside each dish document.
So how do we make modifications to the comments themselves?
How do we get all the list of comments for our dish?
How do we modify a specific comment in the dish, and so on?
So this is what we will see about how to support them using the radius GET,
POST, and DELETE operations on that dishes slash dish id slash comments, and
the dishes slash dish id slash comments slash comment id REST API end points.
1:30
To get started on this exercise again, going back to the dishRouter.
We have already seen how we handle the / end point,
and the /:dishId end point.
Now, much of this work that we do here is all already useful for us.
So what I'm going to do is to copy this code, and
then we will edit that code appropriately to handle the comments and the comment ID.
So I'm going to copy this entire code that we have here, both for the slash, and
the slash core and dish ID, and
then we will paste it right below here again.
And then we will go in and modify each one of them.
So we have seen that if you look back up, the first one
is handling the slash, which will be mounted in the /dishes endpoint.
And the next one is handling the /:dishId.
So the third one should be handling /:dishId/comments.
So going down here, this third dishRouter.route would be
3:00
And then /:commentId.
So now that we have updated this route here, now the next step is to go in and
fix the code in the get, put, post and delete operations here.
So we will start out with the /dishId/comments, end point.
So in case of the /dishId/comments end point, so we will do Dishes.find.
But instead of saying Dishes.find
we will do Dishes.findById.
And so we will find that specific dish that we are looking for.
So here we will look for that rec.params.dishId.
So we will first search for that dish.
And so this will return a specific dish here.
So when it returns that specific dish here.
4:07
Then what we will check for inside here
is that if dish not equal to null.
It is quite possible that the dish doesn't exist.
So if we search for a specific dish with a dish ID, that dish may not exist.
So we need to worry about handling that particular situation.
So let's handle that part inside here.
And so, if it is not null, then that means that the dish exists.
So I'm going to cut this out, and then paste it in there.
And then in this case since that dish is not null,
so we will return that statusCode and the setHeader.
And then this here, we will be returning dish.comments.
Because we are asked to only return the comments for that particular dish.
So we'll say Dishes.findById,
and then reg.params.dishId, and then dish.
And so we will return the dish.comments here.
Otherwise, so this is the else part, so which means that dish does not exist.
So in this case we will construct an error here by saying new Error().
And then we'll say 'Dish' req.params.dishId
5:54
Not found, so this particular dish was not found, so
obviously we won't be able to return the comments for the non-existing dish.
So in this case, so we will create a new Error object, and
then we will set that status in the Error object to 404.
Again, this is 404, not found.
And then we will return next(err).
Now why do we do this?
Because if you return this as an error, as you recall,
this will be handled by your app.js file.
So in the app.js file right at the bottom here, we have the error handler here.
So when it comes in here, this will set the restore status to error.status,
which we have set to 404, so that is what will be returned, and then it'll
simply take that error, and then render that error here.
So that will take care of rendering the errors.
So, this will return the error message back to our client.
So, that is what we're invoking here.
So if the dish does not exist,
we're just going to return that error here from the get operation.
Now, for post, in case of post,
7:20
we are expecting that we would be
returned a dish ID, and then we will look for that dish.
And then we will take the set of comments from the body,
and then push it into the dish there.
So we will say dishes, again here we would have to do that find by ID,
because we are looking for that specific dish here.
So for the post, we'll say dish find by ID.
Then.
>> It's one o'clock.
Dish and so inside here, if the dish exists,
then we will handle the dish appropriately.
If not, then we will have to send error message.
So let me copy this part from the get and
then we will replace this here.
8:23
So obviously if the dish does not exist,
then we're going to return this error here.
But if the dish exists, in that case,
we will return the status code 200 set header.
But before we pass back that value,
what I'm going to do is to say dish.comments.
So we are posting a new set of comments from the dish.
8:56
So we'll say dish.comments.push(req.body) because
the body of the message contains all of the comments that need to be pushed here.
And then we will say dish.save, and so
if the save Returns successfully with the dish here.
So we will send updated dish from here.
9:33
So this part where we are constructing
the statusCode, we will do that inside here,
and then they will send back the,
10:01
So what we are doing is we are saving the dish here.
We are first pushing the comments into the dish there,
the new set of comments into this dish there, and
then we are saving the updated dish here.
After the save, we're going to be returning the updated dish back
10:39
If the dish doesn't exist of course,
they're going to be returning the error saying that the dish does not exist.
So this is for the post.
The put operation of course, is not supported on dishes, so
in this case, we are trying to perform the put operation on the dishes.
11:01
Req.params.dishId /comments.
So this is not allowed, so that's what we are saying for the put operation.
For the delayed operation, what we will do is first find the dish,
so we'll say dish find by ID.
11:22
So delete means that we are removing all the comments from the dish,
not the dish itself.
But we are removing all the comments from the dish.
So in this case, what we would end up doing is as follows.
So if the dish is not null, so
recall that we need to handle it by saying when dish if
the dish is not null then we will remove all the comments from the dish.
So I'm going to copy that code and then paste it in here then we will
edit this code and then delete we will say if
dish is not null, then they will return the dish here.
And so, if dish is not null, the variable would handle this as follows.
So we will have to go in and
delete each of the comments,
so we'll say, for (var i =
(dish.comments.length -1)).
13:24
So this is what we will do to the comments.
And then once we have removed all the comments from the dish,
then we will have to save the dish and then send back.
So earlier also when we modified the dish, this is what we did here.
So I'm going to copy this part.
13:44
And then come in here and
then say Dish.save().
Then we will return the dish
here to indicate the updated dish being returned here.
So this is how we will delete the comments.
So here, we are going in.
Now there is no easy way of literally
pulling out all the comments from the array, when you have a sub document.
So you got to go in and delete each sub document one by one.
So that is what I am doing in this for loop here.
So I'm saying for var i dish.comments.length.
So I'm looking at the array of comments, and then starting from
the last comment in that array all the way to the very first comment.
I'm going in and then deleting comment by comment here by using the remove
14:48
and then comments is the field name, and then I say id here.
So this is how you access a sub document.
I'm inside here,
you'll specify the id of the sub documents that you're trying to access.
So this whole thing will give you access to the sub document, and
then we call the remove method on that sub document.
And so that sub document will be removed from the array of sub documents.
And then after that, after we have deleted all the comments,
I'll save the changes and that's it.
So all my comments will be deleted from the dish there.
Now, we will deal with the next endpoint,
which is dishId/comments/:commentId.
So in this case, we will start by first locating the dish.
And then after we locate the dish, then we have to make sure that the dish exists.
And then deal with the dish.
So I'm going to delete this part and then we'll see,
let's copy this part from the get that we had earlier.
16:09
Because we need to be able to deal with the situation where either the disk
doesn't exist or the disk exists but the comments don't exist.
Or the dish itself does not exist.
So, there are three conditions that I need to test.
So we'll say, if (dish null = null
16:50
Not equal to null.
So which means that the dish itself exists and also the comments exist in partition.
Only then we can then we can send to back a specific comment that has been
asked for.
So in that case, they will say, statusCode is 200.
SetHeader application/json.
And then here, we will send to back dash.comments,
and we are sending back this particular comment.
17:43
(dish == null).
So if the dish is null, then,
of course we will have to indicate that the dish doesn't exist.
And the last condition is the if comment itself is null.
So in that case also I have to indicate that
the comment itself doesn't exist, that particular comment ID doesn't exist.
So in that case, I will say new error
18:16
comment rec.params.commentId.
Not found.
So, three conditions.
First, we have to make sure first that the dish exists and the dish comments exit.
If they do, then I can send back the specific comment.
If not, if the dish itself does not exist on the service
side in the database, then I will indicate that the dish does not exist.
But if the dish exists but the comment does not exist,
then I will send back the message saying the comment does not exist.
Notice that we have to handle all the possible conditions here for the get.
For the post of course,
the post operation is not supported on this end point, so we'll see.
19:09
Comments/' +
req.params.commentId.
So that post operation is not supported on this commentId.
Now what about put?
Put is a more interesting case here.
So again, even for the put,
I have to handle all these possible conditions,
so I'm going to look at this and say okay.
19:50
Let me copy this whole code because we have to handle all this possibilities and
then I'll tell you exactly how we handled put case here.
So in case of put, first of course we need to look at the comment.
So we'll say Dishes.findById(req.params.dishId).
Then, if the dish exists and
the comment itself exists, then I know that I can upgrade the comment.
Otherwise, these two conditions obviously have to be taken care of.
The comment does not exist or the dish does not exist,
these two are already handled by the case.
Now here is the special situation that we have.
So the dish exists and the specific comment that I am looking for also exists.
20:45
Then, what I know is that,
in the body of the message, the updates of the comment is specified.
So I need to update that.
So, somewhere here, you see that when I do modifications, I do a dish save here.
So, I am going to go in and copy a little bit of this code from here.
21:11
Of course, this is not the right thing but
I just need a part of the code From there, so I will comment to the put.
Let me paste it into place here, and
then I'll tell you exactly how we're going to handle this.
21:40
what we know is that, this comment needs to be updated.
So we know that the dish exists and the comment itself exists.
I want to update the fields of the comment.
Now if the comment already exists,
then I don’t want to allow the user to change the author of the comment.
The author should be retained.
The only two fields that I would allow the user update is That rating.
So within the body of the incoming put message,
I can either include the updated rating Or
22:28
These are the only two things that I will allow the user to change.
So if the rating field, if the rating property is in the req body,
the call that the req body will contain the update that we are trying to do.
So in this case, we will say dish, So
we'll say dish.comment, so let me just copy this part.
dish.comments.commentId.
Now this is a simple way of handling this issue here.
So I'm going to, Because there
is no specific way of updating a specific comment which is in a sub-document,
there's no specific method for doing this, so
this is the workaround that I found that seems to work for us.
So we'll say dish.comments.id(req.params.commentId).ra-
ting = req.body.rating.
So I will update the rating.
Similarly, if the comment exists there,
then I will see req.commentId.)comment = req.body.comment.
So that is how I'm going to be updating the Rating and comment.
And once I have updated the rating and the comment, I'm going to save the dish.
And then once I save the dish, then I will send back the reply.
So note that this is the only way that I
found which is easy enough to update an embedded sub-document
inside a document of Mongoose.
There is no explicit way that Mongoose supports for
updating an embedded document, so
this is the workaround that I found that enables us to carry out this operation.
Now for the DELETE operation.
For the DELETE operation, we are deleting only a specific comment so
I will take this information from the,
24:51
Delete of all the comments, and instead of deleting all of the comments,
I am only going to be deleting a specific comment.
So let me copy that over from that delete.
Let me paste it in here, and then we will update this.
So if I am deleting a specific comment.
So I'll first find the dish and if the dish is not null.
Now recall that in this situation I have to handle both the dish not being null and
also the comment not being null.
So I'll say if, Dish not equal to null,
and dish.comments.id parameter not equal to null,
then I know that I have a specific comment that I want to delete.
I am not deleting all of the comments.
I am deleting only a specific comment, here.
So, I'll say dish.comments.id.
And then I am deleting this specific comment here,
which is req.params.commentId,
and remove that particular comment.
And then, I will save the updated dish and then we'll work with that.
Now, the ends part, I need to handle both the situations.
So let me copy this part, else if (dish not equal to null) and so on and
then replace this here.
26:28
So if the dish is null then I will send back the error saying the dish doesn't
exist.
If the comment is null then I'll send back the error saying comment doesn't exist.
So that is it.
This is the update that I'm going to see here.
So for deleting a specific comment, I will first ensure that the dish and
the comment exists, then I will delete the specific comment, and
then I will save the changes to the dish, and
then proceed on with handling the rest of the cases.
That's it.
Let's save the changes, and then look at how this works.
So going to the terminal, if your MongoDB server is not up and running.
So make sure of course that the MongoDB server is up and running.
Let's also start our extra server.
27:20
So once your extra server is up and
running what it'll do is we are now looking specifically at the comments and
then, Performing operations on the comments.
So let's go to the postman and then
27:45
So here I am in postman, so
let me first get the dishes, and now I see that the dishes are all empty.
So let me post a dish to the list of dishes.
So let me post one dish.
So recall that we have this dish here.
So in my postman, I had already done that for the previous exercise,
I'm just going to select that and then post that dish.
And then you see that that particular dish has been posted here down below here.
So you can see that the dish has been created, right there.
So let me now copy that particular dish ID and
then I'm going to now GET,
28:42
That dish here.
So you see that that particular dish exists here.
First, let's GET all the comments.
So if I do a GET on the comments, you notice that all the comments for
the particular dish have been returned.
We can do the post and the delete also.
Let's do a PUT on that.
Obviously, you can't do a PUT on that.
So you notice the PUT operation does not work on that.
Let’s post a new comment.
29:36
Try to post that comment.
So we'll say rating 3 and
then we'll say Test,
Comment Test User,
let's post this comment.
So when you post this comment,
you see that that update dish has been returned here.
30:10
you see that the new comment has been included in there.
So let's copy this whole thing.
Now we will try to go get that particular comment that we have just inserted.
So for that particular comment, this is the ID of the comment,
so let me copy the ID for that specific comment.
Going back to postman,
let me try to retrieve that specific comment by doing the GET operation.
And there you see that that particular comment has been retrieved here.
Now if you try to do a POST on that, it will not work.
So obviously, you see that the POST operation is not allowed on that.
Let's do a PUT operation, On that particular comment.
So for the PUT operation in the body, I'm going to say
Updated Test Comment.
So I'm going to update the comment field of that comment.
So if you send a put on that, you will see that for the specific comment,
the comment has now been updated to reflect the updated test comment.
So you see that the PUT operation on the comments field also works correctly.
31:43
So I can delete the comment.
And then when I delete the comment you see that that comment has disappeared
from the list of comments.
So you see that the DELETE operation also works.
Let's delete all the comments, so I'm going to go in and
delete all the comments.
And then you see that all the comments have been deleted and so
you see that the comments array is now empty.
So now you can see all the GET, PUT, POST and
DELETE operations on the dishes/dishId/comments and
the dishId/comments/commentId,
Rest API endpoints all work as expected.
So with this we complete this exercise.
So in this exercise we have completed the implementation of the /dishes,
REST API end point and supported all the up to allowing us
to manipulate a single dish in the collection of dishes,
a single comment, and also the collection of comments.
This is a good time for you to do a git commit with
the message express REST API with Mongoose part two.
[MUSIC]