John107
John107

Reputation: 2287

Mongoose sort by 'Trending'

I have a collection of posts, and I would like to return them in order of 'trending'.

Currently, I'm returning them like so:

exports.list = async (req, res) => {
  const posts = await Post.find({}).sort([['likes', -1], ['created', -1]]);
  res.json(posts);
};

However, this isn't truly 'trending' posts as it's just returning posts in order of most likes and most recently created. Eg. something with 100 likes created over a year ago, is returned above a post created today with 99 likes. (This is more of a trending of all time method).

I'd like to achieve a way to return the recently created posts with high likes in descending order. Eg. a post with 100 likes created a year ago, is returned below a post with 99 likes created today.

Can I do this inside of mongoose .sort()?

Edit:

// Sample Document
[ 
  {
    likes: 99,
    views: 1,
    _id: 5f9714d33ba3664e3a31b6d4,
    title: 'test',
    author:
     { _id: 5f7b085711ba55fb0413ccd4,
       username: 'Tester',
       __v: 0
     },
    text: 'test',
    comments: [],
    created: 2019-10-26T14:53:49.498Z
  },
  {
    likes: 100,
    views: 53,
    _id: 5f9714d33ba3664e3a31b6c5,
    title: 'test2',
    author:
     { _id: 5f7b085711ba55fb0413ccd4,
       username: 'Tester',
       __v: 0
     },
    text: 'test',
    comments: [],
    created: 2020-10-26T18:26:27.498Z
  },

]

Upvotes: 0

Views: 342

Answers (1)

John107
John107

Reputation: 2287

Perhaps I didn't explain my question very well, but I did find a solution, posting it here in the hopes that It may help others.

In short, I created a trendScore which is calculated by number of likes / (current date - date created), I then added the field to each post and then used the score to sort the order of posts.

exports.list = async (req, res) => {
  const posts = await Post.aggregate([
    {
      $addFields: {
        id: "$_id",
        // I found that 'id' was renamed to '_id', so quick hack to insure existing codebase worked with this change.
        trendScore: {
          $divide: [ "$likes", {$subtract: [new Date(), "$created"]} ]
        }
      }
    },
    {
      $sort: {
        trendScore: -1
      }
    }
  ])
  res.json(posts);
};

The request now returnes trending posts in descending order;

  • 1st Recently added and high likes
  • 2nd Not so recently added and high likes
  • 3rd Recently added and low likes
  • 4th Not so recently added and low likes

The method is there, although calculation could be improved. Hopefully it can be of some help. I would encourage anyone who uses this method to add a $limit as each time the request is made the trendScore is calculated.

Upvotes: 1

Related Questions