I'm facing a challenge with ranking projects based on the number of votes they receive. No matter the vote count, the project always ends up getting ranked as 1.
To address this issue, I developed a function to manage the rank count and a return handler for updating the vote count.
Here is the complete code snippet:
import clientPromise from '../../mongo/mongoDB';
import { ObjectId } from 'mongodb';
// Import collections and DB name from configuration
import { collections, DB } from '@/dynamic/mongoDB';
async function calculateRank(userVotesCollection, projectId) {
const rankData = await userVotesCollection.aggregate([
{
$match: {
project_id: new ObjectId(projectId),
vote_type: "up"
}
},
{
$group: {
_id: "$project_id",
totalUpVotes: { $sum: 1 }
}
},
{
$sort: {
totalUpVotes: -1
}
}
]).toArray();
if (rankData.length === 0) {
return null; // No up-votes for this project
}
// Assign ranks based on sorted order
rankData.forEach((doc, index) => {
doc.rank = index + 1;
});
return rankData[0].rank; // Return rank from the first document (highest up-votes)
}
export default async function handler(req, res) {
if (req.method === 'POST') {
const { project_id, vote_type, user_address } = req.body;
try {
const client = await clientPromise;
const db = client.db(DB);
const projectCollection = db.collection(collections.Token);
const votesCollection = db.collection(collections.userVotes);
// Validate the project ID
if (!ObjectId.isValid(project_id)) {
return res.status(400).json({ error: 'Invalid project ID' });
}
// Update the project's vote counts
let updateFields = {};
if (vote_type === 'up') {
updateFields = { $inc: { project_up_votes: 1 } };
const rank = await calculateRank(votesCollection, project_id);
if (rank !== null) {
const updateResult = await projectCollection.updateOne(
{ _id: new ObjectId(project_id) },
{ $set: { project_rank: rank } }
);
console.log("Updated rank:", updateResult);
}
} else if (vote_type === 'down') {
updateFields = { $inc: { project_down_votes: 1 } };
} else if (vote_type === '10-up') {
updateFields = { $inc: { project_up_votes: 10 } };
} else if (vote_type === '20-up') {
updateFields = { $inc: { project_up_votes: 20 } };
} else {
return res.status(400).json({ error: 'Invalid vote type' });
}
const updateResult = await projectCollection.updateOne(
{ _id: new ObjectId(project_id) },
updateFields
);
if (updateResult.modifiedCount === 0) {
return res.status(404).json({ error: 'Project not found' });
}
// Create a new UserVote document object
const newUserVote = {
user_address,
project_id: new ObjectId(project_id),
vote_type,
};
// Save the UserVote document to the votesCollection
const insertResult = await votesCollection.insertOne(newUserVote);
if (insertResult.insertedCount !== 1) {
return res.status(500).json({ error: 'Failed to save vote' });
}
// Send a success response to the client
res.status(200).json({ message: 'Vote cast successfully' });
} catch (error) {
// Log any errors that occur and send a 500 error response
console.error('Cast vote error: ', error);
res.status(500).json({ error: 'Failed to cast vote' });
}
} else {
res.setHeader('Allow', ['POST']);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}
The highest rank corresponds to 1, inversely proportional to the number of votes received by the project.
I have attempted various methods to accurately calculate the votes.