Displaying MongoDB aggregation pipeline results on the front end?

So, I’m a little new to this… so bear with me. I was able to set up a route with a GET request that products aggregation pipeline results for me in JSON. It’s a pretty simple request that lists “review ratings” from highest to lowest. This is the code, and I have it in a viewController file:

exports.getHighestRatings = catchAsync(async (req, res, next) => {
  const highestRatings = await Review.aggregate([
    {
      $sort: { rating: -1 },
    },
  ]);

  res.status(200).render('aggdisplay', {
    title: 'Fun Stats!',
    data: {
      highestRatings,
    },
  });
  console.log(highestRatings);
});

I’ll note that the console.log here displays the expected content. However, when I try to render anything from highestRatings in my Pug template file, it comes back as “undefined.” This is an example of the pug code:

extends base
block content
article#mainArticle
each rating in highestRatings.rating
span= ${highestRatings.rating}

It was brought to my attention by some crazy guy with a Viking hat that my problem may not be with MongoDB as much as it is with displaying data in JSON format on my front end. So, I’m guessing I should be searching how to properly format and render JSON in my pug template file. Can anyone confirm, provide me with thoughts / feedback? Thank you!

5 Likes

Hey @Christopher_Clark! Welcome to the MongoDB Community! So happy to see you made the jump from Twitter! :heart:

It’s been a couple of years since I’ve used Pug. I believe that the second argument when rendering a Pug template is the data that you want to be sent to the template. Since you are assigning your MongoDB payload to the data key, your MongoDB data needs to be accessed through that key. What happens when you try the following?

extends base
block content
article#mainArticle
each rating in data.highestRatings.rating
     span= ${data.highestRatings.rating}

A better way to send to a payload to your template would be:

res.status(200).render('aggdisplay', {
    title: 'Fun Stats!',
    highestRatings,
});

Then you could use your original template with no modifications (plus it’s “cleaner”).

This is an easy to miss issue (I’ve actually personally done this so many times), and you got 99.999% of the way there by yourself, which is so impressive. :smiling_face_with_three_hearts: Let me know if this solution works for you.

5 Likes

Thank you, Joe! So, since I’m really only sorting from highest to lowest, I was able to find a simpler way to go about this using the following approach in the controller file. The big different being the use of .sort vs. using the aggregation pipeline. Names of the variable have changed from the original example, but same principal.

exports.getTopShips = async (req, res, next) => {
  const topShips = await Ship.find().sort({ ratingsAverage: -1 });
  res.status(200).render('topRated', {
    title: `Top Ships`,
    topShips,
  });
};
1 Like

That’s great! So glad you got it working - your code looks great! Be sure to let me know when you’re done! I’d love to check it out :slight_smile: Also, let me know if you are interested in joining me on Twitch to talk about your project!

1 Like