The Facemash Remake: Recreating a Controversial Rating Platform
Last week my exams got delayed and I have an entire month to spare. I was getting bored so I decided to build something fun. I went to the internet to find something crazy to build and I came up with an Idea.
This idea is based on the famous incident that happened at Harvard when the founder of Facebook (Meta) hacked into the university's database and used student's images (girls to be specific) on a website where people can rate two random students based on their hotness.
Though I didn't hack into any university's database instead I let people upload their images so that we can rate them(crazy isn't it). The original FaceMash website was built using PHP and MySQL but I wanted to go with the trend. I initially was thinking of building the website using ReactJS and Firebase but Firebase doesn't have any standard method to fetch random documents so I decided to make my own API using NodeJs and mongodb.
Let's go through the development process.
Building the Rest API was fairly simple, the only tricky thing was understanding the Elo Rating Algorithm and fetching random documents from the database but some Google searches and ChatGPT prompts were enough to teach both things.
For those of don't know what the heck is Elo rating algorithm, It is a mathematical method of calculating the relative skill level in a two-player game. In simple words, each player has a numerical rating that represents their skill level. Higher scores indicate stronger players.
After a game ratings are updated based on the outcome of the game compared to the expected outcome. if a higher-rated player wins, their rating is increased slightly but if a lower-rated opponent wins their rating increases significantly. Conversely, the higher-rated player's rating increases more if they lose to a lower-rated opponent.
You can read more about the Elo algorithm on the internet but this is the brief concept. here is how it works in code.
exports.addVote = catchAsyncError(async (req, res, next) => {
try {
const { winnerId, loserId } = req.body;
const winner = await Person.findById(winnerId);
const loser = await Person.findById(loserId);
console.log(winner, loser);
if (!winner || !loser) {
return next(new CustomError("Invalid Winner or Loser", 401));
}
const expectedWinner =
1 / (1 + Math.pow(10, (loser.score - winner.score) / 400));
const expectedLoser = 1 - expectedWinner;
const kFactor = 32;
const newWinnerScore = winner.score + kFactor * (1 - expectedWinner);
const newLoserScore = loser.score + kFactor * (0 - expectedLoser);
winner.score = newWinnerScore;
winner.wins += 1;
loser.score = newLoserScore;
loser.lose += 1;
await winner.save();
await loser.save();
res.status(200).json({ message: "Votes recorded successfully" });
} catch (err) {
console.error(err);
res.status(500).json({ error: "Internal server error" });
}
});
Now let's talk about how I'm fetching random documents from MongoDB.
I am using $sample aggregation to fetch random users but sometimes it gives duplicate documents and to prevent this behavior I am making sure that both the documents don't have the same _id.
exports.getRandomPerson = catchAsyncError(async (req, res, next) => {
const winner = req.query.winner;
console.log(winner);
const aggregationPipeline = [];
if (winner) {
if (mongoose.Types.ObjectId.isValid(winner)) {
aggregationPipeline.push({
$match: { _id: { $ne: new mongoose.Types.ObjectId(winner) } },
});
} else {
return next(new CustomError("Invalid winner id!", 401));
}
}
aggregationPipeline.push({ $sample: { size: 2 } });
let randomPersons;
while (true) {
randomPersons = await Person.aggregate(aggregationPipeline);
if (!randomPersons) break;
if (randomPersons[0]._id !== randomPersons[1]._id) break;
}
res.json(randomPersons);
});
For the front-end part, I am using React Js with Tailwind CSS. It is fairly simple If know a little bit about React Js you will understand what is going on there.
So this was my attempt to build the Facemash. I hope you enjoyed the journey and learned something new. The code for this project is available on GitHub. You can do whatever you want to do with the code.
It was Shanu Malik, thanks for reading.
We'll see each other in the next article!
Subscribe to my newsletter
Read articles from shanu Malik directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by