Field-mask the scoreboard self-user read (R5)
getScoreboard loaded the full user doc just to use 5 fields. Add getUserForScoreboard using getAll with a fieldMask so only displayName, photoUrl, tierPoints, favoriteTeamCode, and rankSnapshot are fetched, cutting per-request bandwidth. The short-lived me-rank cache (meRankCache, 30s) already covers the rank-count side of R5.
This commit is contained in:
parent
fa7767d172
commit
f0b01a2dc0
@ -36,6 +36,44 @@ export async function getUser(uid: string): Promise<User | null> {
|
||||
return snap.exists ? (snap.data() as User) : null;
|
||||
}
|
||||
|
||||
/** 스코어보드 "me" 계산에 필요한 최소 필드만 담는 형태. */
|
||||
export interface ScoreboardSelfUser {
|
||||
displayName: string;
|
||||
photoUrl?: string;
|
||||
tierPoints?: number;
|
||||
favoriteTeamCode?: TeamCode;
|
||||
rankSnapshot?: RankSnapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* 스코어보드 응답의 "me" 계산에 필요한 필드만 fieldMask로 읽어온다.
|
||||
* 전체 user doc(streak/티켓/notifications 등) 대신 5개 필드만 전송받아 bandwidth를 줄인다.
|
||||
*
|
||||
* @returns 필요한 필드 부분집합. 문서가 없으면 `null`.
|
||||
*/
|
||||
export async function getUserForScoreboard(
|
||||
uid: string
|
||||
): Promise<ScoreboardSelfUser | null> {
|
||||
const ref = firestore.collection(COLLECTION).doc(uid);
|
||||
const [snap] = await firestore.getAll(ref, {
|
||||
fieldMask: [
|
||||
"displayName",
|
||||
"photoUrl",
|
||||
"tierPoints",
|
||||
"favoriteTeamCode",
|
||||
"rankSnapshot",
|
||||
],
|
||||
});
|
||||
if (!snap.exists) return null;
|
||||
const data = snap.data() as Partial<User>;
|
||||
const self: ScoreboardSelfUser = { displayName: data.displayName ?? "" };
|
||||
if (data.photoUrl) self.photoUrl = data.photoUrl;
|
||||
if (data.tierPoints !== undefined) self.tierPoints = data.tierPoints;
|
||||
if (data.favoriteTeamCode) self.favoriteTeamCode = data.favoriteTeamCode;
|
||||
if (data.rankSnapshot) self.rankSnapshot = data.rankSnapshot;
|
||||
return self;
|
||||
}
|
||||
|
||||
export interface ScoreboardUserEntry {
|
||||
uid: string;
|
||||
displayName: string;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { MemCache } from "../lib/memCache";
|
||||
import {
|
||||
countUsersAboveTierPoints,
|
||||
getUser,
|
||||
getUserForScoreboard,
|
||||
} from "../repositories/userRepository";
|
||||
import {
|
||||
readScope,
|
||||
@ -51,7 +51,7 @@ export async function getScoreboard(
|
||||
uid: string,
|
||||
type: ScoreboardType
|
||||
): Promise<ScoreboardResponse> {
|
||||
const user = await getUser(uid);
|
||||
const user = await getUserForScoreboard(uid);
|
||||
if (!user) throw new HttpError(404, `user not found: ${uid}`);
|
||||
|
||||
const teamCode = type === "team" ? user.favoriteTeamCode : undefined;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user