Skip to content

Commit d7de4ad

Browse files
committed
fix: use predicted ratings if needed
1 parent b0bd7ef commit d7de4ad

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

services/users.js

+60
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,63 @@ const getContestParticipantsData = async (contest) => {
274274
return [];
275275
}
276276
let total = contest.rankings.length;
277+
278+
let participantsMap = new Map();
279+
contest.rankings.forEach((rank, index) => {
280+
const id = getUserId(rank._id, rank.data_region);
281+
participantsMap.set(id, index);
282+
});
277283
let result = new Array(total),
278284
failed = [];
279285
let limit = 500;
280286

287+
// if there was a contest withing last 24 hours then most probably ratings for last contest are not going to be updated on leetcode
288+
// so it's better to use our predicted ratings for those participants who participated in the last contest
289+
const lowLimit = contest.startTime - 24 * 60 * 60 * 1000; // within 24 hours
290+
const upLimit = contest.startTime;
291+
const lastContest = await Contest.findOne(
292+
{ startTime: { $gte: lowLimit, $lt: upLimit } },
293+
{ _id: 1 }
294+
).sort({ startTime: -1 });
295+
296+
// if there was a contest within last 24 hours
297+
if (lastContest) {
298+
// participants' username list
299+
const handles = contest.rankings.map((rank) => {
300+
return rank._id;
301+
});
302+
303+
// get rating predictions from last contest
304+
const predictedRatings = await Contest.aggregate([
305+
{
306+
$project: {
307+
_id: 1,
308+
"rankings._id": 1,
309+
"rankings.current_rating": 1,
310+
"rankings.delta": 1,
311+
"rankings.data_region": 1,
312+
},
313+
},
314+
{ $match: { _id: lastContest._id } },
315+
{ $unwind: "$rankings" },
316+
{ $match: { "rankings._id": { $in: handles } } },
317+
]);
318+
319+
// add predicted ratings'data in result
320+
if (predictedRatings) {
321+
predictedRatings.map((itm) => {
322+
itm = itm.rankings;
323+
const id = getUserId(itm._id, itm.data_region);
324+
if (participantsMap.has(id)) {
325+
result[participantsMap.get(id)] = {
326+
isFirstContest: false, // always false because user participated in minimum two contests
327+
rating: itm.current_rating + itm.delta,
328+
};
329+
}
330+
});
331+
}
332+
}
333+
281334
const getCurrentRatingHelper = async (index, isFailed = false) => {
282335
let userData = await getCurrentRating(
283336
contest.rankings[index].user_slug,
@@ -289,15 +342,21 @@ const getContestParticipantsData = async (contest) => {
289342
failed.push(index);
290343
}
291344
};
345+
346+
// get progress in percentage
292347
const getPercentage = (done, total) => {
293348
if (total <= 0) {
294349
return -1;
295350
}
296351
return Math.round(((done * 100) / total) * 100) / 100;
297352
};
353+
354+
// TODO: fetch ratings in one query for all the users who are already saved in db
355+
298356
for (let i = 0; i < total; i += limit) {
299357
let promises = [];
300358
for (let j = 0; j < limit && i + j < total; j++) {
359+
if (result[i + j]) continue; // skip if already fetched
301360
promises.push(getCurrentRatingHelper(i + j));
302361
}
303362
await Promise.all(promises);
@@ -308,6 +367,7 @@ const getContestParticipantsData = async (contest) => {
308367
)}%)`
309368
);
310369
}
370+
311371
let failedRanks;
312372
const retry = async (limit) => {
313373
console.log("Total failed: ", failedRanks.length, "limit: ", limit);

0 commit comments

Comments
 (0)