The stats helper

The primary responsibility of the stats helper module is to gather some totals for our application. These stats are for things such as the total number of images uploaded, the total number of comments, the total views for all the images combined, and the total likes for all the images combined. Your first inclination might be to assume that we are going to query MongoDB for all the images and loop through every image to track all of the views and totals. That's one way to do it, but it's pretty inefficient. Fortunately, MongoDB has some built-in functionalities which make generating these kinds of values a snap.

As we are going to be making a number of calls to MongoDB, we are going to rely
on the async.parallel function again, much like we did in the sidebar module. The original helpers/stats.js file was very bare bones, so let's completely replace that file with this new version, which uses parallel:

const models = require('../models'),
async = require('async');

module.exports = (callback) => {
async.parallel([
(next) => {
next(null, 0);
},
(next) => {
next(null, 0);
},
(next) => {
next(null, 0);
},
(next) => {
next(null, 0);
}
], (err, results) => {
callback(null, {
images: results[0],
comments: results[1],
views: results[2],
likes: results[3]
});
});
};

This code does exactly what the module originally did, only it's a little more verbose! I'm pretty sure we don't want to just return 0 for all of our stats forever, though, as that'd be pretty useless and unimpressive, to say the least! Let's update the each function to properly query MongoDB and get some stats. Looking at the object returned in the callback in the last function, we can see that we already defined the order of the functions that are being executed in parallel. Let's start with images. Replace the next(null, 0); line in the first function with the following code snippet:

models.Image.count({}, next); 

Easy! Just use MongoDB's count method to find the total number of documents in the images collection matching any criteria (the first parameter). Then, we just pass the next function as the callback, because coincidentally enough, the parameter signatures match. If we didn't want to use shorthand here, we could write this the long way, as follows:

models.Image.count({}, (err, total) => {
next(err, total);
});

However, who feels like typing all that when you don't have to! Let's do the same thing for the second function in the parallel array for total comments. Replace the next(null, 0); line in the second function with the following line of code:

models.Comment.count({}, next); 

Again, this was a piece of cake!

Now, the next two functions are going to be a little different, but they are almost identical to each other. What we want to do with next is get the total views and likes for every image. We can't use MongoDB's count method, because that only counts individual documents in a collection. We need to use MongoDB's aggregate functionality instead.

Using aggregate, we can perform a mathematical operation, such as $sum, to tally results for us. Replace the next(null, 0); line in the third function with the following code snippet:

models.Image.aggregate({
$group: {
_id: '1',
viewsTotal: { $sum: '$views' }
}
}, (err, result) => {
var viewsTotal = 0;
if (result.length > 0) {
viewsTotal += result[0].viewsTotal;
}
next(null, viewsTotal);
});

Using MongoDB's aggregate function, we are telling MongoDB to group every document together and sum up all of their views into a single new field called viewsTotal. The resulting collection that is returned to the callback function is an array of documents with the _id and viewsTotal fields. In this case, the results array will only contain a single document with the grand total, because we weren't that tricky with our aggregate functionality. If there aren't any images in the collection at all, we need to handle that and check accordingly. Finally, the next callback function is called with the actual value for viewsTotal.

Let's use the same exact functionality to total up the likes for all images. Replace the next(null, 0); line of code in the fourth and final function in parallel with the following code snippet:

models.Image.aggregate({
$group: {
_id: '1',
likesTotal: { $sum: '$likes' }
}
}, (err, result) => {

var likesTotal = 0;
if (result.length > 0) {
likesTotal += result[0].likesTotal;
}
next(null, likesTotal);
});

Now that the sidebar helper module has been updated and is complete with the async.parallel functionality, let's make a minor tweak to our sidebar module to ensure we are calling the Stats module correctly so that it's properly asynchronous. The original line in helpers/sidebar.js was:

next(null, Stats()); 

Replace that line of code with this slightly different version:

Stats(next); 

Last but not least, let's take care of the most popular helper module for the images sidebar.

..................Content has been hidden....................

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