In my quest to create a sorting algorithm that identifies the most popular questions, I rely on the following equation:
Rating = (AV * (1 / 50)) + (AL * 3) - (AD * 6)
The parameter I use for sorting is called Rating. The questions with the highest ratings are considered the trendiest.
AV represents average views, calculated by dividing Views by days ago
AL represents average likes, calculated by dividing Likes by days ago
AD represents average dislikes, calculated by dividing Dislikes by days ago
Below is the data structure for the documents we are sorting:
const Question = mongoose.model(
"Question",
new Schema({
title: { type: String, required: true },
text: { type: String },
authorUsername: { type: String, required: true },
dateCreated: {},
answers: { type: Array, required: true },
likes: { type: Array, required: true },
dislikes: { type: Array, required: true },
tag: { type: String, required: true },
views: {type: Array, required:true},
})
);
Here's an example of a question:
document:_id:620935985f6865b4e85c333d,
title:"How do i make a lemon?",
text:"yeet",
authorUsername:"SweetWhite",
dateCreated:2022-02-13T16:45:12.598+00:00,
answers: Array,
likes:
0:1,
1:"SweetWhite",
dislikes: Array,
0:0,
tag:
"Social",
views:Array,
0:1,
1:"SweetWhite",
__v:0
Note that the length of the views, likes, and dislikes arrays are stored in the first item which is a number, so when using $size it will be one too big.
Is there anyone who can utilize Question.aggregate with the given equation and document to filter out the top 15 trendy questions (highest rating)?
Thanks!
EDIT: Here is the code snippet I have implemented:
router.get('/questions/hot', async (req,res,next) => {
try{
const results = await Question.aggregate([
/*{$arrayElemAt:[{$ifNull:["$likes",[0]]}, 0]},
{$arrayElemAt:[{$ifNull:["$dislikes",[0]]}, 0]},
{$arrayElemAt:[{$ifNull:["$views",[0]]}, 0]}*/
{$project: {rating: {$add:[
{$divide:
[
{$divide: [{$arrayElemAt:[{$ifNull:["$views",[0]]}, 0]}, 1]},
50
]},
{$subtract:
[
{$multiply: [{$divide: [{$arrayElemAt:[{$ifNull:["$likes",[0]]}, 0]}, 1]}, 3]},
{$multiply: [{$divide: [{$arrayElemAt:[{$ifNull:["$dislikes",[0]]}, 0]}, 1]}, 6]}
]
}
]}
}},
{$sort: {rating:-1}},
{$limit: 15}
]).exec();
console.log(results)
const questions = await Promise.all(results.map(({_id}) => Question.findOne({_id}).exec()));
res.render('content', { whichOne: 5, user: req.user, questions:questions});
}
catch(err){
next(err);
}
});
Although the algorithm is working correctly overall, the issue lies in the calculation of the average likes/dislikes/views per day. Currently, I am dividing by 1 instead of considering the actual days elapsed since creation. Any insights on how to incorporate this time factor would be greatly appreciated.