The second part of this exercise deals with
the various get put post and delete operations on sub-documents inside the document.
As we saw in the example for dishes,
we saw that the comments are included inside the dish itself as a sub-document,
in the way we 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 a 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 various get put post and delete operations on
the dish dishes slash dish ID slash comments and the dishes
slash dish ID slash comments slash comment ID REST API endpoints.
To get started on this exercise,
again, going back to the dish router,
they have already seen how we handle the slash endpoint and the slash dish ID endpoint.
Now, much of this work that we do here is 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 golden 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 on the slash dishes endpoint.
And the next one is handling the slash dish ID.
So the third one should be handling slash dish ID slash comments.
So going down here,
this third dish router route would be slash dish ID slash comments.
And then the last one, of course,
would be slash dish ID slash
comments and then slash colon comment ID.
So now that we have updated these routes 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 off with the slash dish ID slash comments endpoint.
So in case of the slash dish ID slash comments endpoint,
so we will do dishes find but instead of saying dishes find,
we will do dishes find by
ID and so we will find the specific dish that we are looking for.
So here, we will look for that req params dish ID,
so we will first search for the dish,
and so this will return a specific dish.
So when it returns that specific dish here,
then what they 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 the dish is not null,
so we will return the status code and the set header 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 find by ID,
then req parameters dish ID and then dish."
And so we will return the dish comments here.
Otherwise, so this is the else part.
So which means that the dish does not exist.
So in this case,
we would construct an error here by saying new errors and then we'll say
dish req params dish ID 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 the 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'll 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 rest or status to error dot status,
which we had set to 404,
so that is what will be returned,
and then it will 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.
That is what we are 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,
we are expecting that they would be
returned a dish ID and then we will look for the 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 will have to do the find by id because we are looking for the specific dish here.
So for the post, we'll say dish find by ID then dish,
and so inside here,
if the dish exists,
then we will handle the dish appropriately.
If not, then we will have to send the error message.
So let me copy this part from the get and then,
we will replace this here.
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 the value,
what I am going to do is to say dish comments,
so we are posting a new set of comments for the dish.
So we'll say dish comments push req body.
Because the body of the message contains all 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 the updated dish from here.
So this part where we are constructing the status code,
we will do that inside here and then we will send the back the
Res.json and the dish that we obtained here.
So, what we are doing is we are saving the dish here.
We're first pushing the comments into the dish there,
the new set of comments into the dish here,
and then we are saving the updated dish here.
Then after the save,
we're going to be returning the updated dish back to the user here.
Then if there is an error,
then we will handle the error just like we have done here.
If the dish doesn't exist, of course,
we are 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, req.params.dishId/comments.
So, this is not allowed.
So, that's what we are saying for the PUT operation.
For the delete operation,
what we will do is first find the dish.
So, we'll say dish.findbyId.
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,
recall that we need to handle it by saying then dish.
If the dish is not null,
then we would remove all the comments from the dish.
So, I'm going to copy that code and then paste it in here,
and then we will edit this code, then delete.
We will see if dish is not null,
then they will return the dish here.
So, if dish is not not null,
the wat we would handle this is 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) i>= 0; i--).
So, we are literally going in and removing each comment.
So, we'll say
dish.comments.id(dish.comments[i]._id).
We'll say remove.
So, we are going to be removing each of the dishes,
one under each of the comments one by one.
So, this is what we will do to the comments.
Then once we have removed all the comments for the dish,
then we will have to save the dish and then send back.
So, earlier also when we modify the dish,
this is what we did here.
So, I'm going to copy this part,
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 have 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 operation on the subdocument.
So, the way we will access a subdocument is by saying
dish and then comments is the field name and then I say id here.
So, this is how you access a subdocument,
and inside here you will specify the id of the subdocuments that you're trying to access.
So, this whole thing will give you access to the subdocument,
and then we call the remove method on the subdocument,
and so that subdocument will be removed from the array of subdocuments.
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 then dish.
Now, we will deal with the next end point which is dishIdcomments/:commentId.
So, in this case,
we will start out 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 say let's copy this part from the git that we had earlier
because we need to be able to deal with the situation
where either the dish doesn't exist or the dish 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 && dish.comments.id (req.params.commentId)!=
null, so which means that the dish itself exists and also the comments exist in the dish,
only then we can send back a specific comment that has been asked for.
So, in that case,
we will say statusCode is 200, setHeader application json,
and then here we will send back dish.comments,
and we are sending back this particular comment.
So, that is the specific comment that we are sending max.
So, this will allow us to retrieve a specific comment from the set of comments.
Now, we'll say else if dish equal to null.
So the dishes null,
then of course we will have to indicate that the dish doesn't exist and
the last condition is if the 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
comment req.params.commentId not found.
So, three conditions.
First, you have to make sure first that the dish exists and the dish comments exist,
if they do then i can send back the specific comment,
if not, if the dish itself does not exist on the server 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.
So, notice that they have to handle all the possible conditions here for the GET.
For the POST of course,
the post operation is not supported on this endpoint,
so we'll say
comments slash req.params.commentId.
So, the POST operation is not supported on this comment Id. Now what about PUT?
PUT is a more interesting case here.
So, again even for the put,
I to have to handle all these possible conditions,
so I am going to look at this and say, okay for this,
let me copy this whole code because we have to handle
all these possibilities and then I'll tell you exactly how we handle the PUT case here.
So, in case of PUT,
first of course we need to locate the carnage.
So they'll say dishes find by Id req param Id,
then if the dish exists and the comment itself exists,
then I know that I can update the comment.
Otherwise, these two conditions obviously have to be taken care of,
that comment does not exist or the dish does not exist.
These two are already handled by that case.
Now, here is the special situation that we have.
So,if the dish exists and the specific comment that I am looking for also exists,
then what I know is that in the body of the message,
the update for the comment is specified.
So I need to update that.
So, somewhere here 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,
of course this is not the right thing but I just need a part of the code from there,
so I will come into the PUT.
Let me paste it into place here and
then I'll tell you exactly how they are going to handle this.
Because I need the dish save part.
So, how do we handle the update to a specific comment?
So for the update to a specific comment,
what do 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 current.
Now, if a comment already exists then I don't want
to allow the user to change the author of the comment,
the author should retained.
The only two fields that I would allow the user update is the rating.
So within the body of the incoming PUT message,
I can either include
the updated rating
or the updated comment.
These are the only two things that I will allow the user to change.
So if the if the rating property ies indirect body to call that the body
will contain the update that we are trying to do so in this case we will say dish.
So we'll say dish comments,
so let me just copy this part.
Dish comment comment Id.
Now this is a simple way of handling this issue here.
Because there is no specific way of updating
a specific comment which is in a sub-document,
there is 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 req parameter comment Id rating equal to req body.rating.
So I will update the rating.
Similarly, if the comment exists there,
then I will say req comment Id comment req body comment.
So, that is how I'm going to be updating the rating and the comment,
and I once say about updated the rating and the comment,
and they will 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 a 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 deleter for all the comments
and instead of deleting all the comments
I'm only going to be deleting a specific comment.
So, let me copy that over from the 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.
If the dish is not null,
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'm not deleting all the comments,
I am deleting only a specific comment here.
So, I'll say dish comments id and then I am deleting the specific comment here which
is req.params.commentId and remove
that particular comment and then I will save the updated dish and then move on with that.
Now, the else 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.
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 doing here.
For deleting a specific comment,
I will first ensure that the dish and the comment
exist 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.
Going to the terminal,
I see MongoDB server is not up and running so let's start there.
Make sure, of course,
that the MongoDB server is up and running,
let's also start our express server.
Once your express server is up and running,
what we will 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 check out what we have in the database and then try to modify the comments.
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 list of dishes so let me post one dish.
Recall that we have this dish her,
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.
You can see that the dish has been created right there.
Let me now copy that particular dish id and then I'm going to
now get 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 that particular dish have been returned.
We can do the post and the delete also.
Let's do a put on that and obviously you can't do a put on
back so you notice that the put operation doesn't work on that.
Let's post a new comment.
So to post a new comment we'll go into the body,
and then let me cut out all these and then we'll edit one of
the comments and then
try to post that comment.
So, we'll say rating three and then we'll
say test comment, test user.
Let's post this comment.
When you post this comment,
you see that the update dish has been returned here and you see that within
this dish you see that the new comment has been included in there.
So, let's copy this whole thing.
Now, we will try to get that particular comment that we have just inserted.
For that particular comment this is the id of that 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 a get operation.
There you see that that particular comment has been retrieved here.
Now, if you're try to do a post on that,that 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, if I were to 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.
If you're saying to 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.
Let's delete that comment,
so I can delete the comment and then when I delete the comment you'll
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.
Then you see that all the comments have been deleted,
and so you see that the comments area is now empty.
So, now you can see them all the get, put, post,
and delete operations on
the dishes/dishId/ comments
and the dishes/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 slash dishes,
REST API endpoint and supported all the way up to
allowing us to manipulate a single dish,
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.