@@ -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