import { getDocs } from "firebase/firestore";
//3) 문서 조회 - 전체 문서 조회 (getDocs, collection)
const getBooks = async () => {
const querySnap = await getDocs(collection(db, "books"));
console.log('조회된 문서(도서) 갯수:', querySnap.size);
console.log('조회된 문서가 비어있는지:', querySnap.empty);
console.log('조회된 문서 목록(배열):', querySnap.docs); // [QueryDocumentSnapshot, ...]
// querySnap.docs.forEach((doc) => console.log(doc.id, doc.data()))
const books = querySnap.docs.map((doc) => {
return {
id: doc.id,
...doc.data()
}
});
// console.log(books);
console.table(books)
}
getBooks();
import { getDocs } from "firebase/firestore";
firebase/firestore에서 getDocs 함수를 불러옵니다.getDocs는 Firestore의 컬렉션에서 문서들을 가져오는 함수입니다.const getBooks = async () => {
getBooks라는 비동기 함수를 선언합니다.async를 붙이면 함수 내부에서 await를 사용하여 비동기 작업을 동기 코드처럼 처리할 수 있습니다.const querySnap = await getDocs(collection(db, "books"));
collection(db, "books")
books라는 컬렉션을 선택합니다.getDocs(...)
await
querySnap
QuerySnapshot입니다.querySnap.docs → 실제 문서 배열querySnap.size → 문서 개수querySnap.empty → 문서가 비어있는지 여부// querySnap.docs.forEach((doc) => console.log(doc.id, doc.data()))
const books = querySnap.docs.map((doc) => {
return {
id: doc.id,
...doc.data()
}
});
map을 사용하여 querySnap.docs 배열을 새로운 배열로 변환합니다.doc)의 id와 data()를 합쳐서 객체 형태로 만듭니다.books 배열은 Firestore 문서 전체를 보기 좋은 배열 형태로 변환한 것.console.table(books)
books 배열을 테이블 형태로 콘솔에 출력합니다.getBooks();
getBooks 함수를 실행합니다.Firestore에서 필요한 함수(import) 가져오기
import { getDocs } from "firebase/firestore";
비동기 함수 선언 (async)
const getBooks = async () => { ... }
Firestore 컬렉션 지정하고 문서 조회 (getDocs)
const querySnap = await getDocs(collection(db, "books"));
필요하면 조회 결과 확인 (console.log 등)
문서 배열을 map으로 변환하여 원하는 형태로 가공
const books = querySnap.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
결과 출력 (console.table)
함수 호출 (getBooks();)
정리 : Firestore에서 문서 조회 → 배열로 변환 → 콘솔에 보기 좋게 출력 순서로 이해
books라는 새로운 배열을 만드는가?querySnap.docs 자체는 QueryDocumentSnapshot 객체의 배열입니다.
각 요소는 Firestore 내부의 문서 객체라서 그냥 쓰기엔 불편합니다.
doc.data()를 쓰려면 이렇게 해야 합니다:querySnap.docs.forEach(doc => {
console.log(doc.data());
});
그런데 실제 개발에서는 문서 ID도 같이 필요한 경우가 많습니다.
book/:id 경로로 연결그래서 ID와 데이터를 함께 객체로 묶은 배열을 만들어서 쓰는 게 실용적입니다.
return { id: doc.id, ...doc.data() } 의미doc.id → 문서 고유 IDdoc.data() → 문서에 저장된 필드 전체 객체...doc.data()는 스프레드 연산자입니다.
즉, 객체 안의 모든 키와 값을 한꺼번에 펼쳐서 새로운 객체 안에 넣겠다는 뜻입니다.
예시를 보면 이해가 쉬워요:
// 문서 데이터가 이렇게 저장되어 있다고 가정
doc.id = "bk001";
doc.data() = { title: "React Book", author: "지원", price: 30000 };
// return 구문
return {
id: doc.id, // "bk001"
...doc.data() // title, author, price 모두 펼쳐짐
};
// 결과 객체
{
id: "bk001",
title: "React Book",
author: "지원",
price: 30000
}
즉, 문서 ID까지 함께 포함한 객체를 쉽게 얻기 위해 이렇게 작성하는 거예요.
만약 ID가 필요 없으면 doc.data()만 써도 되지만, 대부분 실제 서비스에서는 문서 식별용 ID가 필수입니다.
전체 문서 조회 후 리스트 표시할 때
ID가 필요한 경우
배열 형태로 다루기 편하게 가공하고 싶을 때
즉, books 배열은 프론트엔드에서 바로 반복문 돌려서 UI 렌더링할 수 있게 만든 편의용 배열입니다.
💡 요약
| 질문 | 답 |
|---|---|
| 왜 새로운 배열을 만드는가? | Firestore 객체 그대로 쓰면 불편해서, ID와 데이터를 묶은 실용적 배열로 만들기 위해 |
{ id: doc.id, ...doc.data() } 의미 | 문서 ID + 문서 데이터 전체를 하나의 객체로 합쳐 반환 |
doc.data()만 쓰면 안 되나? | 가능하지만, 문서 ID가 필요하면 불가능 → 대부분 서비스에서는 ID 필요 |
querySnap.docs.map(...)를 통해 각 문서를 id + 데이터 형태로 변환하면books입니다.즉 구조를 그림으로 보면:
querySnap.docs = [ doc1, doc2, doc3, ... ] // Firestore 문서 객체 배열
books = querySnap.docs.map(doc => ({
id: doc.id,
...doc.data()
}))
books = [
{ id: "bk001", title: "React Book", author: "지원", price: 30000 },
{ id: "bk002", title: "Vue Book", author: "세윤", price: 25000 },
...
]
id + 데이터로 합쳐서 만든 것books 배열 → 모든 문서를 이런 객체 형태로 모은 배열즉, books가 바로 UI에서 반복문 돌리거나 테이블로 보여주기 쉽게 가공한 최종 배열