@@ -274,10 +274,63 @@ const getContestParticipantsData = async (contest) => {
274
274
return [ ] ;
275
275
}
276
276
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
+ } ) ;
277
283
let result = new Array ( total ) ,
278
284
failed = [ ] ;
279
285
let limit = 500 ;
280
286
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
+
281
334
const getCurrentRatingHelper = async ( index , isFailed = false ) => {
282
335
let userData = await getCurrentRating (
283
336
contest . rankings [ index ] . user_slug ,
@@ -289,15 +342,21 @@ const getContestParticipantsData = async (contest) => {
289
342
failed . push ( index ) ;
290
343
}
291
344
} ;
345
+
346
+ // get progress in percentage
292
347
const getPercentage = ( done , total ) => {
293
348
if ( total <= 0 ) {
294
349
return - 1 ;
295
350
}
296
351
return Math . round ( ( ( done * 100 ) / total ) * 100 ) / 100 ;
297
352
} ;
353
+
354
+ // TODO: fetch ratings in one query for all the users who are already saved in db
355
+
298
356
for ( let i = 0 ; i < total ; i += limit ) {
299
357
let promises = [ ] ;
300
358
for ( let j = 0 ; j < limit && i + j < total ; j ++ ) {
359
+ if ( result [ i + j ] ) continue ; // skip if already fetched
301
360
promises . push ( getCurrentRatingHelper ( i + j ) ) ;
302
361
}
303
362
await Promise . all ( promises ) ;
@@ -308,6 +367,7 @@ const getContestParticipantsData = async (contest) => {
308
367
) } %)`
309
368
) ;
310
369
}
370
+
311
371
let failedRanks ;
312
372
const retry = async ( limit ) => {
313
373
console . log ( "Total failed: " , failedRanks . length , "limit: " , limit ) ;
0 commit comments