fix: Meilisearch 검색 결과에서도 전체 멤버 '프로미스나인' 처리

- searchSchedules: 검색 시 현재 활동 멤버 수 캐시
- formatScheduleResponse: 전체 멤버인 경우 '프로미스나인'으로 대체
- syncAllSchedules: 동기화 시 탈퇴 멤버 제외, 멤버 수 캐시 갱신

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
caadiq 2026-01-22 20:56:38 +09:00
parent 9515db712d
commit 2a50a07a29

View file

@ -15,6 +15,9 @@ const logger = createLogger('Meilisearch');
const INDEX_NAME = 'schedules'; const INDEX_NAME = 'schedules';
const MIN_SCORE = config.meilisearch.minScore; const MIN_SCORE = config.meilisearch.minScore;
// 캐시된 현재 활동 멤버 수 (동기화 시 갱신)
let cachedActiveMemberCount = null;
/** /**
* 영문 자판으로 입력된 검색어인지 확인 * 영문 자판으로 입력된 검색어인지 확인
*/ */
@ -39,6 +42,19 @@ export async function resolveMemberNames(db, query) {
return members.map(m => m.name); return members.map(m => m.name);
} }
/**
* 현재 활동 멤버 조회 캐시
*/
async function getActiveMemberCount(db) {
if (cachedActiveMemberCount === null) {
const [[{ count }]] = await db.query(
'SELECT COUNT(*) as count FROM members WHERE is_former = 0'
);
cachedActiveMemberCount = count;
}
return cachedActiveMemberCount;
}
/** /**
* 일정 검색 * 일정 검색
* @param {object} meilisearch - Meilisearch 클라이언트 * @param {object} meilisearch - Meilisearch 클라이언트
@ -52,6 +68,8 @@ export async function searchSchedules(meilisearch, db, query, options = {}) {
const SEARCH_LIMIT = 1000; const SEARCH_LIMIT = 1000;
try { try {
// 현재 활동 멤버 수 캐시 (formatScheduleResponse에서 사용)
await getActiveMemberCount(db);
const index = meilisearch.index(INDEX_NAME); const index = meilisearch.index(INDEX_NAME);
const searchOptions = { const searchOptions = {
@ -128,10 +146,15 @@ export async function searchSchedules(meilisearch, db, query, options = {}) {
*/ */
function formatScheduleResponse(hit) { function formatScheduleResponse(hit) {
// member_names를 배열로 변환 // member_names를 배열로 변환
const members = hit.member_names let members = hit.member_names
? hit.member_names.split(',').map(name => name.trim()).filter(Boolean) ? hit.member_names.split(',').map(name => name.trim()).filter(Boolean)
: []; : [];
// 전체 멤버인 경우 "프로미스나인"으로 대체
if (cachedActiveMemberCount && members.length === cachedActiveMemberCount) {
members = ['프로미스나인'];
}
// source 객체 구성 (Meilisearch에는 URL 없음) // source 객체 구성 (Meilisearch에는 URL 없음)
let source = null; let source = null;
if (hit.category_id === CATEGORY_IDS.YOUTUBE && hit.source_name) { if (hit.category_id === CATEGORY_IDS.YOUTUBE && hit.source_name) {
@ -199,7 +222,13 @@ export async function deleteSchedule(meilisearch, scheduleId) {
*/ */
export async function syncAllSchedules(meilisearch, db) { export async function syncAllSchedules(meilisearch, db) {
try { try {
// DB에서 모든 일정 조회 // 현재 활동 멤버 수 캐시 갱신
const [[{ count }]] = await db.query(
'SELECT COUNT(*) as count FROM members WHERE is_former = 0'
);
cachedActiveMemberCount = count;
// DB에서 모든 일정 조회 (탈퇴 멤버 제외)
const [schedules] = await db.query(` const [schedules] = await db.query(`
SELECT SELECT
s.id, s.id,
@ -216,7 +245,7 @@ export async function syncAllSchedules(meilisearch, db) {
LEFT JOIN schedule_categories c ON s.category_id = c.id LEFT JOIN schedule_categories c ON s.category_id = c.id
LEFT JOIN schedule_youtube sy ON s.id = sy.schedule_id LEFT JOIN schedule_youtube sy ON s.id = sy.schedule_id
LEFT JOIN schedule_members sm ON s.id = sm.schedule_id LEFT JOIN schedule_members sm ON s.id = sm.schedule_id
LEFT JOIN members m ON sm.member_id = m.id LEFT JOIN members m ON sm.member_id = m.id AND m.is_former = 0
GROUP BY s.id GROUP BY s.id
`); `);