학습 목표와 사전 지식
목표: 컬렉션·문서 경로와 CRUD 요청의 의미를 한 메모 데이터 흐름으로 연결합니다.
사전 지식: JavaScript 모듈/async, Firebase 초기화·로그인
Firestore는 컬렉션 안에 문서를 저장합니다. 문서 ID와 필드의 사용자 UID는 다른 값이며, 읽기·쓰기 호출을 제공하는 SDK와 그 호출을 허용하는 Rules는 함께 설계해야 합니다.
| 경로·호출 | 의미 |
|---|---|
| notes | 컬렉션 |
| notes/자동ID | 문서 |
| addDoc | 새 자동 ID 생성; 재시도하면 중복 생성 가능 |
| setDoc | 지정 ID 쓰기; 기본은 덮어쓰기, merge 선택 가능 |
| updateDoc | 기존 문서 일부 수정; 없는 문서는 실패 |
| deleteDoc | 해당 문서 삭제; 하위 컬렉션 자동 삭제 아님 |
src/notes.js · 전체 학습 모듈; 초기화된 db와 인증 관찰이 끝난 user 전달
import { addDoc, collection, deleteDoc, doc, getDoc, getDocs,
query, updateDoc, where } from 'firebase/firestore';
export async function createNote(db, user, text) {
if (!user) throw new Error('로그인이 필요합니다.');
const created = await addDoc(collection(db, 'notes'), { ownerId: user.uid, text });
return created.id;
}
export async function readNote(db, id) {
const snapshot = await getDoc(doc(db, 'notes', id));
return snapshot.exists() ? { id: snapshot.id, ...snapshot.data() } : null;
}
export async function listMyNotes(db, user) {
if (!user) throw new Error('로그인이 필요합니다.');
const result = await getDocs(query(collection(db, 'notes'), where('ownerId', '==', user.uid)));
return result.docs.map((item) => ({ id: item.id, ...item.data() }));
}
export async function editNote(db, id, text) {
await updateDoc(doc(db, 'notes', id), { text });
}
export async function removeNote(db, id) {
await deleteDoc(doc(db, 'notes', id));
}
규칙과 문서 구조를 맞추기
이 모듈의 notes는 ownerId와 text만 사용하며 permission-denied 해결 글의 notes 규칙과 대응합니다. UI의 user 인자 검사는 사용자 안내이고 서버의 Rules가 실제 소유권을 검증합니다. 사용자 A의 문서 ID를 B가 알아도 읽기·수정·삭제가 거부되어야 합니다. 목록 조회에는 같은 ownerId 조건을 붙여 전체 컬렉션을 무작정 읽지 않습니다.

완료 응답 이후 다음 작업하기
const id = await createNote(db, user, “첫 메모”)로 실제 반환 ID를 보관하고 readNote(db, id), editNote(db, id, “수정”), removeNote(db, id) 순서로 await합니다. 예시 ID를 가정해 다른 문서를 수정하지 마세요. 없어진 문서를 읽는 결과와 권한 거부 예외는 구분합니다. 읽기 함수가 null을 반환하는 경우는 허용된 요청에서 snapshot.exists()가 false인 경우입니다.
다음 단계: 쿼리와 정합성
목록이 커지면 limit와 커서 페이지네이션을 추가합니다. 복합 조건·정렬에 필요한 인덱스를 확인하세요. 여러 문서가 같이 바뀌어야 하면 batch나 transaction을 검토합니다. 단일 문서 삭제가 하위 데이터를 지우지 않으므로 계정 탈퇴 정리는 별도 범위입니다. 선택 필드에 undefined를 넣지 말고 저장할 값을 명시적으로 구성합니다.

개발 프로젝트 확인 순서
A 계정으로 메모 하나 생성→ID로 읽기→수정→목록 확인→삭제를 실행합니다. 각 Promise 실패는 UI에서 catch하여 메시지를 표시합니다. B 계정과 비로그인 상태에서 A의 ID로 동일 호출을 해 거부를 확인합니다. 이 글은 CRUD 개념 모듈이며 로그인 화면·프로젝트 생성·클라우드 검증을 끝낸 완성 앱으로 제시하지 않습니다.
직접 확인할 결과
모듈 node –check
A/B/비로그인 CRUD 절차 제공
실제 CRUD·Rules 미실행
검증 범위와 기준일
공식 문서 확인일: 2026-09-13. 웹 SDK 예제는 모듈형 API 기준입니다. 이 글의 코드·구조 정적 검토와 실제 클라우드 인증·저장·배포 검증을 구분합니다. 본인 개발 Firebase 프로젝트의 실제 인증·권한·배포 요청은 이 편집 환경에서 실행하지 않았습니다.
이어서 학습하기
공식 문서
이 글이 도움이 되었나요?
Firebase 학습 순서
필수 13개 · 전체 19개
읽음 기록 관리
전체 과정 목차 (19개)
- 필수 길잡이 · Firebase 실무 로드맵: Auth, Firestore, Storage, Functions
- 필수 학습 · Firebase 초기화 구조: Next.js firebase.ts 설계 기준
- 필수 학습 · Firebase Authentication 사용 기준: 로그인 유지와 비밀번호 재설정
- 필수 학습 · Firebase 보안 규칙 설계: Firestore와 Storage 권한 관리하기
- 필수 학습 · Firestore CRUD 사용법: 컬렉션 구조와 읽기 쓰기 흐름 현재 글
- 필수 학습 · Firebase Auth Context 설계: 로그인 권한과 라우팅 관리하기
- 필수 학습 · Firebase Storage 이미지 업로드 사용법: 상품 이미지 관리 흐름 만들기
- 필수 학습 · Firebase Custom Claims 사용법: 관리자 권한 구분하기
- 필수 학습 · Firebase Functions v2 사용법: 트리거 배포 Secret 처리
- 필수 학습 · Firestore seed data 설계: 리뷰 더미 데이터 구조 잡기
- 선택 참고 · Firebase 배포 제외 파일 설정: firebase.json의 ignore 사용법
- 선택 참고 · Firebase Firestore 인덱스 삭제 질문 해결: 배포 중 안전하게 판단하기
- 선택 참고 · Firebase Auth unauthorized-domain 오류 해결: 로그인 도메인 설정 확인
- 선택 참고 · Firebase permission-denied 오류 해결: Firestore Rules 체크리스트
- 선택 참고 · Firebase Storage 이미지 오류 해결: 403·404·token·Rules 확인법
- 선택 참고 · Firebase CORS 오류 해결: Storage 이미지 업로드가 막힐 때 확인할 설정
- 필수 선수 · Firebase 실무 오류 해결 모음: Storage, Firestore, Auth 체크리스트
- 필수 학습 · Firestore undefined 오류 해결: 선택 필드가 저장을 막을 때
- 필수 학습 · Firestore arrayUnion 중첩 배열 오류: 배열을 그대로 넘기면 실패하는 이유
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.