BE
[Firebase] 색인 추가하기
| 서론

ListPage와 같이, 특정 사용자(userId)의 모든 회고 리스트 가져오는 기능을 구현하고 있는 상황에서, 데이터 통신에 실패했다는 로그를 보게 되었습니다.
이 부분에 대해서 알아보니, 바로 복합쿼리가 일어나서 발생한 문제였습니다.
const q = query(
collection(db, 'retrospectives'),
where('userId', '==', userId),
orderBy('createdAt', 'desc') // 최신순 정렬
);현재 이 코드를 보면, userId로 필터링하면서 createdAt으로 정렬한 데이터를 요청하는 것을 볼 수 있습니다.
즉, 두 개 이상의 필드를 동시에 사용하는 쿼리(where + orderBy)를 실행할 때,
자동 인덱스가 없어서 생긴 오류였음을 알게 되었습니다.
Firestore는 단일 필드(where 또는 orderBy 하나)에는 자동 인덱스를 생성하지만,
두 개 이상의 필드를 동시에 사용하는 경우엔 수동 생성이 필요합니다.
이를 해결할 수 있는 것이 바로, '색인'이라는 개념이었습니다.
오늘은 색인에 대한 개념과 색인을 설정하는 방법에 대해서 공유해보려고 합니다.
| 색인이란?
Firestore에서 색인(Index) 은 데이터를 빠르고 효율적으로 검색하기 위해 미리 정리해둔 데이터 구조를 의미합니다.
쉽게 말해, 데이터베이스의 “목차”나 “색인표” 같은 역할을 하는 것이죠.
Firestore는 기본적으로 모든 단일 필드(single field) 에 자동으로 색인을 만들어줍니다.
그래서 단순히 한 필드만 기준으로 조회할 때는 별다른 설정 없이 빠르게 검색할 수 있습니다.
하지만 두 개 이상의 조건(예: where + orderBy)을 함께 사용하는 복합 쿼리(composite query) 의 경우,
Firestore가 어떤 순서로 데이터를 정렬하고 필터링할지 미리 알 수 없기 때문에, 직접 색인을 생성해줘야 정상적으로 동작합니다.
즉, “색인(Index)”은 Firestore가 데이터를 빠르고 정확하게 찾아내도록 도와주는 검색 지도(Search Map)같은 것입니다.색인을 제대로 설정하면 쿼리 성능이 향상되고, 데이터 검색 시 오류를 방지할 수 있습니다.
| 색인을 설정하는 방법
그렇다면, 색인은 어떻게 생성할까요?
1) 먼저, Firebase 콘솔에 접속한 뒤, Firebase Database 메뉴에서 '색인'을 클릭합니다.
- 이후, '색인 만들기' 버튼을 클릭합니다.

2) 컬렉션 ID, 색인 생성할 필드, 쿼리 범위를 지정합니다.

(1) 컬렉션 ID 입력
: 지금 프로젝트에서 회고 데이터를 저장하고 있는 컬렉션 이름을 입력합니다.
(2) 필드 추가하기
: 아래의 표와 같은 예시처럼 필요한 필드명과 정렬 방법을 선택합니다.
순서 | 필드 경로 | 정렬 순서 | 설명 |
1 | userId | 오름차순(Ascending) | where('userId', '==', userId) 조건용 |
2 | createdAt | 내림차순(Descending) | orderBy('createdAt', 'desc') 정렬용 |
3) 쿼리 범위 설정한 뒤, '만들기' 버튼을 클릭합니다.
: 하단의 “쿼리 범위” 드롭다운 메뉴를 컬렉션(Collection) 으로 선택합니다.
4) 결과 확인

화면 하단에 “색인 생성 중…” 이라는 메시지가 잠시 뜨고, 이후 색인 목록에 새 항목이 추가됩니다.
1~2분 정도 기다리면, “상태: 활성(Active)” 으로 바뀝니다.→ 이때부터 해당 쿼리(userId + createdAt)가 정상 작동합니다.
| 결론

신기하게도 해당 색인을 추가한 뒤에 데이터 요청이 성공적으로 이루어진 것을 확인할 수 있었습니다.
색인이라는 개념이 조금 생소할 수 있지만, 색인을 제대로 설정함을 통해 쿼리 성능을 향상시키고, 데이터 검색 시 오류를 방지할 수 있다는 점을 배울 수 있었습니다.
이번 경험을 통해 단순히 데이터를 “조회한다”는 행위도 내부적으로는 색인(index) 을 기반으로 효율적인 탐색이 이루어진다는 사실을 알게 되었습니다.
또한, Firestore는 기본적인 단일 필드 색인을 자동으로 생성해주지만,
조금만 복잡한 쿼리(where + orderBy 등)를 사용하면 직접 색인을 만들어야 한다는 점이 인상 깊었습니다.