diff --git a/server/src/external/mongo/indexes.ts b/server/src/external/mongo/indexes.ts index f0fd1514f..cf6eefdb1 100644 --- a/server/src/external/mongo/indexes.ts +++ b/server/src/external/mongo/indexes.ts @@ -24,11 +24,13 @@ const staticIndexes: Partial> = { index({ scoreID: 1 }, UNIQUE), index({ chartID: 1, userID: 1 }), index({ game: 1, playtype: 1, userID: 1 }), + index({ chartID: 1 }), ], "personal-bests": [ index({ chartID: 1, userID: 1 }, UNIQUE), index({ chartID: 1, "scoreData.percent": 1 }), index({ game: 1, playtype: 1, userID: 1 }), + index({ chartID: 1 }), ], sessions: [ // lol @@ -83,6 +85,7 @@ const staticIndexes: Partial> = { "user-private-information": [index({ userID: 1 }, UNIQUE), index({ email: 1 }, UNIQUE)], "fer-settings": [index({ userID: 1 }, UNIQUE)], counters: [index({ counterName: 1 }, UNIQUE)], + "class-achievements": [index({ game: 1, playtype: 1, timeAchieved: 1 })], }; const indexes: Partial> = staticIndexes; @@ -94,12 +97,16 @@ for (const game of ServerTypeInfo.supportedGames) { index( { songID: 1, difficulty: 1, playtype: 1, isPrimary: 1 }, { unique: true, partialFilterExpression: { isPrimary: { $eq: true } } } - ) + ), + index({ songID: 1 }), + index({ playtype: 1 }) ); } else { indexes[`charts-${game}` as Databases] = [ index({ chartID: 1 }, UNIQUE), index({ songID: 1, difficulty: 1, playtype: 1, isPrimary: 1 }, UNIQUE), + index({ songID: 1 }), + index({ playtype: 1 }), ]; } diff --git a/server/src/utils/queries/charts.ts b/server/src/utils/queries/charts.ts index 17f7d57cc..67b37f91d 100644 --- a/server/src/utils/queries/charts.ts +++ b/server/src/utils/queries/charts.ts @@ -236,8 +236,6 @@ export function FindChartOnARCID(game: "iidx" | "ddr" | "jubeat" | "sdvx", arcID * Returns the N most popular charts for this game + playtype. * Popularity is determined by how many scores match in the score * collection. - * - * Performance of this is untested. */ export function FindChartsOnPopularity( game: Game, diff --git a/server/src/utils/queries/stats.ts b/server/src/utils/queries/stats.ts new file mode 100644 index 000000000..01d932a48 --- /dev/null +++ b/server/src/utils/queries/stats.ts @@ -0,0 +1,41 @@ +import { Game, Playtypes, gameClasses, IDStrings, integer } from "tachi-common"; +import NodeCache from "node-cache"; +import db from "external/mongo/db"; +import { ONE_HOUR } from "lib/constants/time"; + +const classDistCache = new NodeCache(); + +export async function GetClassDistribution( + game: Game, + playtype: Playtypes[Game], + className: gameClasses.GameClassSets[IDStrings] +) { + const cacheKey = `${game}:${playtype}:${className}`; + const cache = classDistCache.get(cacheKey); + + if (!cache) { + const distribution = (await db["game-stats"].aggregate([ + { + $match: { + game, + playtype, + }, + }, + { + $group: { + _id: `$classes.${className}`, + count: { $sum: 1 }, + }, + }, + ])) as { _id: string; count: integer }[]; + + // Converts {_id: "kaiden", count: 3} to {"kaiden": 3}, more or less. + const convert = Object.fromEntries(distribution.map((e) => [e._id, e.count])); + + classDistCache.set(cacheKey, convert, ONE_HOUR); + + return convert; + } else { + return cache; + } +}