Listing 27.8 implements the route handling code for the CommentThread
model. Two routes are handled: getComment()
and addComment()
. Due to the size of the file, the code for these two routes is broken down in the following sections.
The getComment()
route handler looks up a single CommentThread
document, based on the _id
field passed in as commentId
in the GET
request query string.
04 exports.getComment = function(req, res) {
05 CommentThread.findOne({ _id: req.query.commentId })
06 .exec(function(err, comment) {
07 if (!comment){
08 res.json(404, {msg: 'CommentThread Not Found.'});
09 } else {
10 res.json(comment);
11 }
12 });
13 };
The addComment()
route handler, shown in Listing 27.9, is quite a bit more complex than getComment()
and involves a chain of functions to support updating nested comments. The logic flow for adding new comments is as follows:
1. The client sends a request that includes the CommentThread
ID, a parent comment ID to add the new comment to, and a JSON object that represents the new comment.
2. The /comment/add
route handler calls addComment()
.
3. The CommentThread
object is located using the req.body.rootCommentId
value from the POST
data.
4. A new Reply
object named newComment
object is created from the req.body.newComment
value from the POST
data.
5. addComment()
is run recursively, looking through the nested comments until it finds a comment that matches the req.body.parentCommentId
passed in from the POST
body.
6. The new comment is pushed into the replies
array of the parent comment.
7. The updateCommentThread()
method uses the following update()
operation to update the replies
field in the CommentThread
document with the one that now contains the updated comment:
CommentThread.update({ _id: commentThread.id },
{$set:{replies:commentThread.replies}}).exec();
8. A success or failure response is sent back to the client.
14 exports.addComment = function(req, res) {
15 CommentThread.findOne({ _id: req.body.rootCommentId })
16 .exec(function(err, commentThread) {
17 if (!commentThread){
18 res.json(404, {msg: 'CommentThread Not Found.'});
19 } else {
20 var newComment = Reply(req.body.newComment);
21 newComment.username = generateRandomUsername();
22 addComment(req, res, commentThread, commentThread,
23 req.body.parentCommentId, newComment);
24 }
25 });
26 };
27 function addComment(req, res, commentThread, currentComment,
28 parentId, newComment){
29 if (commentThread.id== parentId){
30 commentThread.replies.push(newComment);
31 updateCommentThread(req, res, commentThread);
32 } else {
33 for(var i=0; i< currentComment.replies.length; i++){
34 var c = currentComment.replies[i];
35 if (c._id== parentId){
36 c.replies.push(newComment);
37 var replyThread = commentThread.replies.toObject();
38 updateCommentThread(req, res, commentThread);
39 break;
40 } else {
41 addComment(req, res, commentThread, c,
42 parentId, newComment);
43 }
44 }
45 }
46 };
47 function updateCommentThread(req, res, commentThread){
48 CommentThread.update({ _id: commentThread.id },
49 {$set:{replies:commentThread.replies}})
50 .exec(function(err, savedComment){
51 if (err){
52 res.json(404, {msg: 'Failed to update CommentThread.'});
53 } else {
54 res.json({msg: "success"});
55 }
56 });
57 }
Listing 27.10 shows the full implementation of the comments_controller.js
file that provides route handling involving the Comment
model. The Comment
model route handler code loads the schema for both the CommentThread
and Reply
models. The CommentThread
model provides the ability to look up CommentThread
documents as well as update them when new comments are added. The Reply
model creates the Reply
object when a new comment is added.
The comment controller code provides a function that randomly generates a username for testing purposes:
function generateRandomUsername(){
//typically the username would come from an authenticated session
var users=['DaNae', 'Brad', 'Brendan', 'Caleb', 'Aedan', 'Taeg'];
return users[Math.floor((Math.random()*6))];
}
Typically the username would come from the session in the Request
object, but session code is omitted from this example to keep it easier to follow.
01 var mongoose = require('mongoose'),
02 CommentThread = mongoose.model('CommentThread'),
03 Reply = mongoose.model('Reply'),
04 exports.getComment = function(req, res) {
05 CommentThread.findOne({ _id: req.query.commentId })
06 .exec(function(err, comment) {
07 if (!comment){
08 res.json(404, {msg: 'CommentThread Not Found.'});
09 } else {
10 res.json(comment);
11 }
12 });
13 };
14 exports.addComment = function(req, res) {
15 CommentThread.findOne({ _id: req.body.rootCommentId })
16 .exec(function(err, commentThread) {
17 if (!commentThread){
18 res.json(404, {msg: 'CommentThread Not Found.'});
19 } else {
20 var newComment = Reply(req.body.newComment);
21 newComment.username = generateRandomUsername();
22 addComment(req, res, commentThread, commentThread,
23 req.body.parentCommentId, newComment);
24 }
25 });
26 };
27 function addComment(req, res, commentThread, currentComment,
28 parentId, newComment){
29 if (commentThread.id== parentId){
30 commentThread.replies.push(newComment);
31 updateCommentThread(req, res, commentThread);
32 } else {
33 for(var i=0; i< currentComment.replies.length; i++){
34 var c = currentComment.replies[i];
35 if (c._id== parentId){
36 c.replies.push(newComment);
37 var replyThread = commentThread.replies.toObject();
38 updateCommentThread(req, res, commentThread);
39 break;
40 } else {
41 addComment(req, res, commentThread, c,
42 parentId, newComment);
43 }
44 }
45 }
46 };
47 function updateCommentThread(req, res, commentThread){
48 CommentThread.update({ _id: commentThread.id },
49 {$set:{replies:commentThread.replies}})
50 .exec(function(err, savedComment){
51 if (err){
52 res.json(404, {msg: 'Failed to update CommentThread.'});
53 } else {
54 res.json({msg: "success"});
55 }
56 });
57 }
58 function generateRandomUsername(){
59 //typically the username would come from an authenticated session
60 var users=['DaNae', 'Brad', 'Brendan', 'Caleb', 'Aedan', 'Taeg'];
61 return users[Math.floor((Math.random()*5))];
62 }