Index - retrieving an image model

The primary responsibility of the index function in our image controller is to retrieve the details for a single, specific image, and display that via its viewModel. In addition to the details for the actual image, the comments for an image are also displayed on the page in the form of a list. Whenever an image is viewed, we also need to update the view count for the image and increment it by one.

Begin by editing the controllers/image.js file and updating the list of required modules at the top, to include our models module:

const fs = require('fs'), 
path = require('path'), 
sidebar = require('../helpers/sidebar'), 
Models = require('../models');

We also want to strip viewModel down to its most basic form, exactly as we did in the home controller. Replace the existing viewModel object variable with this new, lighter version:

var viewModel = { 
image: {}, 
comments: [] 
}; 

After defining a blank viewModel, let's include a find call on the Image model so that we can look up an image specifically by its filename:

Models.Image.findOne({
filename: { $regex: req.params.image_id }
},
(err, image) => {
if (err) { throw err; }
if (image) {
// to do...
} else {
res.redirect('/');
}
});

In the preceding code, we are using the Models module's Image model and performing findOne, which is identical to find, except it will only ever return a single document (matching or not), instead of an array like find returns. By convention, we use a singular variable name in our callback's second parameter versus a plural one, just so we, as developers, can easily tell whether we are working with a single object or an array/collection of objects.

The query object we provide as the first parameter matches the filename field of an image document using MongoDB's regex filter and compares this to req.params.image_id, which is the value of the parameter in the URL as defined in our routes file. The URL for an image page will always be http://localhost:3300/images/abcdefg, where abcdefg will be the value of req.params.image_id. If you recall, we are randomly generating this value in the create function when an image is uploaded.

After checking to make sure our err object isn't null, we then check to make sure our image object is also not null. If it's not null, that means a model was returned from MongoDB; so, we found our image, and we're good to go. If an image model wasn't returned, because we tried searching for an image by a filename that doesn't exist, we simply redirect the user back to the home page.

Let's now populate our viewModel by inserting the following lines into the area where we have the // to do... placeholder comment:

image.views = image.views + 1; 
viewModel.image = image; 
image.save(); 

We attach the image model that was returned from findOne to our viewModel.image property, but not before incrementing the views property of that model by 1 (so that we represent our actual plus one view as we load the page). Since we modified the model (by incrementing its view count), we need to ensure that it's saved back to MongoDB, so we call the model's save function.

Now that viewModel has been updated with the image model and the view
count has been incremented and saved, we need to retrieve a list of comments associated with the image. Let's include a little bit more code to query the Comment model and find any comments that belong to the image. Insert the following block of code immediately after image.save(); from earlier:

Models.Comment.find({ image_id: image._id }, {}, {
sort: {
'timestamp': 1
}
},
(err, comments) => {
if (err) { throw err; }

viewModel.comments = comments;

sidebar(viewModel, (viewModel) => {
res.render('image', viewModel);
});
}
);

Using find on our Comment model, we can pass in an object that contains our query as the first parameter; in this case, we are specifying that we want all comments where the image_id field is equal to the _id property of the main image model
we attached to our viewModel earlier.

That code might look a little odd, so let's elaborate. Remember that the image object that is returned from the original Models.Image.findOne() call is available throughout the entire scope of that callback function. No matter how deep we get nesting callback functions, we will always have access to that original image model. Therefore, we can access it and its properties inside the callback function that fires when our Model.Comment.find() has executed.

Once inside the find callback of Comment, we attach the comments array that was returned to our viewModel and then call our sidebar function exactly as we did when we first opened the controller and started editing this index function.

As a review, here is the entire index function inside the controllers/image.js file after it's been completely updated:

index: (req, res)=>{ 
        var viewModel = { 
            image: {}, 
            comments: [] 
        }; 
 
        Models.Image.findOne({ filename: { $regex: req.params.image_id } }, 
            (err, image)=>{ 
                if (err) { throw err; } 
                if (image) { 
                    image.views = image.views + 1; 
                    viewModel.image = image; 
                    image.save(); 
 
                    Models.Comment.find( 
                        { image_id: image._id}, 
                        {}, 
                        { sort: { 'timestamp': 1 }}, 
                        (err, comments)=>{ 
                            viewModel.comments = comments; 
                            sidebar(viewModel, (viewModel)=>{ 
                                res.render('image', viewModel); 
                            }); 
                        } 
                    ); 
                } else { 
                    res.redirect('/'); 
                } 
            }); 
    }

Let's quickly recall all of the index controller's responsibilities and tasks:

  1. Create a new empty viewModel object.
  2. Create the findOne imagefindOneimage model, where the filename is a regex match to the URL image_id parameter.
  3. Increment the found views of the image by one.
  4. Attach the found image model to viewModel.
  5. Save the image model since its views have been updated.
  6. Find all comments with the image_id property equal to the _id of
    the original image model.
  7. Attach the array of found comments to viewModel.
  8. Render the page using sidebar, passing in the viewModel, and the
    callback function.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.237.29