diff --git a/apps/api/src/guild/leaderboards/guild-leaderboard.service.ts b/apps/api/src/guild/leaderboards/guild-leaderboard.service.ts index 430f00294..8fc11aec9 100644 --- a/apps/api/src/guild/leaderboards/guild-leaderboard.service.ts +++ b/apps/api/src/guild/leaderboards/guild-leaderboard.service.ts @@ -49,28 +49,27 @@ export class GuildLeaderboardService extends LeaderboardService { protected async getAdditionalStats( ids: string[], fields: string[] - ): Promise { + ): Promise> { const selector = fields.reduce((acc, key) => { acc[key] = true; return acc; }, {} as Record); + selector.id = true; selector.nameFormatted = true; - return await Promise.all( - ids.map(async (id) => { - const guild = await this.guildModel - .findOne() - .where("id") - .equals(id) - .select(selector) - .lean() - .exec(); + const guilds = await this.guildModel + .find({ id: { $in: ids } }) + .select(selector) + .lean() + .exec(); + return new Map( + guilds.map((guild) => { const additionalStats = flatten(guild) as LeaderboardAdditionalStats; additionalStats.name = additionalStats.nameFormatted; - return additionalStats; + return [guild.id, additionalStats]; }) ); } diff --git a/apps/api/src/leaderboards/leaderboard.service.ts b/apps/api/src/leaderboards/leaderboard.service.ts index 58a15af98..2ab33356d 100644 --- a/apps/api/src/leaderboards/leaderboard.service.ts +++ b/apps/api/src/leaderboards/leaderboard.service.ts @@ -13,6 +13,7 @@ import { InjectRedis } from "#redis"; import { Injectable, InternalServerErrorException } from "@nestjs/common"; import { type LeaderboardEnabledMetadata, getLeaderboardField, getLeaderboardFields } from "@statsify/schemas"; import { LeaderboardQuery } from "@statsify/api-client"; +import { Logger } from "@statsify/logger"; import { Redis } from "ioredis"; const DAYS_IN_WEEK = { @@ -29,6 +30,8 @@ export type LeaderboardAdditionalStats = Record & { name: string }; @Injectable() export abstract class LeaderboardService { + private readonly logger = new Logger("LeaderboardService"); + public constructor(@InjectRedis() protected readonly redis: Redis) {} public async addLeaderboards( @@ -143,8 +146,9 @@ export abstract class LeaderboardService { ] ); - const data = leaderboard.map((doc, index) => { - const stats = additionalStats[index]; + const data = leaderboard.flatMap((doc) => { + const stats = additionalStats.get(doc.id); + if (!stats) return []; if (extraDisplay) { const extraDisplayValue = stats[extraDisplay] ?? extraDisplayMetadata?.default; @@ -168,15 +172,23 @@ export abstract class LeaderboardService { if (!hidden) fields.push(field); fields.push(...additionalValues); - return { + return [{ id: doc.id, fields, name: stats.name, position: doc.index + 1, highlight: doc.index === highlight, - }; + }]; }); + const missing = leaderboard.length - data.length; + + if (missing) { + this.logger.warn( + `${missing} of ${leaderboard.length} rows on ${constructor.name} ${field} page ${top / PAGE_SIZE} have no document` + ); + } + const fields = []; if (!hidden) fields.push(fieldName); fields.push(...additionalFieldMetadata.map(({ fieldName }) => fieldName)); @@ -265,7 +277,7 @@ export abstract class LeaderboardService { protected abstract getAdditionalStats( ids: string[], fields: string[] - ): Promise; + ): Promise>; private async getLeaderboardFromRedis( constructor: Constructor, diff --git a/apps/api/src/player/leaderboards/player-leaderboard.service.ts b/apps/api/src/player/leaderboards/player-leaderboard.service.ts index 5877de527..1ba9e365d 100644 --- a/apps/api/src/player/leaderboards/player-leaderboard.service.ts +++ b/apps/api/src/player/leaderboards/player-leaderboard.service.ts @@ -48,28 +48,27 @@ export class PlayerLeaderboardService extends LeaderboardService { protected async getAdditionalStats( ids: string[], fields: string[] - ): Promise { + ): Promise> { const selector = fields.reduce((acc, key) => { acc[key] = true; return acc; }, {} as Record); selector.displayName = true; + selector.uuid = true; - return await Promise.all( - ids.map(async (id) => { - const player = await this.playerModel - .findOne() - .where("uuid") - .equals(id) - .select(selector) - .lean() - .exec(); + const players = await this.playerModel + .find({ uuid: { $in: ids } }) + .select(selector) + .lean() + .exec(); + return new Map( + players.map((player) => { const additionalStats = flatten(player) as LeaderboardAdditionalStats; additionalStats.name = additionalStats.displayName; - return additionalStats; + return [player.uuid, additionalStats]; }) ); }