firebase ver 8 with React (3) Firestore
no sql이고, mongoDB랑 비슷합니다.
MongoDB가 DB - 컬렉션 - 도큐먼트의 구조로 이루어져있듯, firestore도 컬렉션-도큐먼트의 구조를 가지고 있습니다.
doc: https://firebase.google.com/docs/reference/js/firebase.firestore
firebase.firestore() 관련 : https://firebase.google.com/docs/reference/js/firebase.firestore.Firestore
Type들
문서를 보면 아래 타입들이 자주 등장합니다.(이후에 다른 기능을 써보면서 더 추가해보겠음)
CollectionReference
https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference
collection를 wrapping한 것입니다. 특정 document를 가져오라고 쿼리를 날릴 대상입니다. 단순히 add, get 같은 메서드를 사용하여 document를 넣고 읽고 할 수도 있습니다. onSnapshot으로 Observer를 붙여 event-driven으로 만들 수도 있습니다.
DocumentReference
https://firebase.google.com/docs/reference/js/firebase.firestore.DocumentReference
document를 wrapping한 것입니다. 특정 document를 조작할 수 있습니다. delete, set, update ...
가장 쉽게는 firebase.firestore().doc(`path`) 꼴로 가져올 수 있습니다.
onSnapshot으로 Observer를 붙여 event-driven으로 만들 수도 있습니다.
Query
https://firebase.google.com/docs/reference/js/firebase.firestore.Query#orderby
where절이라던가, Query를 반환하는 경우가 있습니다. 생각보다 단순하니 문서를 직접 훑어볼 것을 추천드립니다.
QuerySnapshot => 여러 개의 DocumentSnapshot를 감싸고 있습니다. docs() 메서드를 통해서 여러 개의 QueryDocumentSnapshot를 가져올 수 있습니다. 그 외에 empty()를 통해서 문서 쿼리 결과가 빈 값인지 등 여러 조작을 할 수 있습니다. firebase의 document를 담은 배열로 생각하면 편할 듯.
QueryDocumentSnapshot => 쿼리의 결과로 받은 도큐먼트입니다. 쿼리의 실직적인 firestore의 도큐먼트를 감싸고 있는 녀석입니다. data() 메서드로 도큐먼트를 직접 출력할수도 있고 여러 메서드를 통해 도큐먼트의 여러 속성들을 살펴볼 수도 있습니다.
CollectionReference의 메서드들
https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference#where
create
CollectionReference https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference
// CollectionReference 반환
firebase.firestore().collection("books");
// books라는 컬렉션에 {...} 도큐먼트를 넣어라
firebase.firestore().collection("books").add({name: "uly", pages: 235});
read
QuerySnapshot https://firebase.google.com/docs/reference/js/firebase.firestore.QuerySnapshot
QueryDocumentSnapshot https://firebase.google.com/docs/reference/js/firebase.firestore.QueryDocumentSnapshot
아니 depth가 뭐 이렇게 깊어 어휴;;
사실, QuerySnapshot에서 QueryDocumentSnapshot을 get으로 뽑아내는 것은 생각보다 깊네요.
// CollectionReference의 get 메서드는 QuerySnapshot 반환
const bookQuerySnapShot = firebase.firestore().collection("books").get();
// QueryDocumentSnapshot의 data 메서드로 도큐먼트 출력
bookQuerySnapShot.forEach(QueryDocumentSnapshot => console.log(QueryDocumentSnapshot.data());
delete, update
firebase에는 '경로'가 있습니다. '[collection]/[documentId]' 꼴입니다. 해당 경로를 전달해주고, 조작하면 됩니다.
firebase.firestore().doc(`books/${book.id}`).delete();
firebase.firestore().doc(`books/${book.id}`).update({ name: newName });
where
왜 이렇게 만들었는지 의문인 메서드입니다. 어노테이션이 처음 봤을 때 이상하다고 느꼈슴...
where (fieldPath : string | FieldPath, opStr : WhereFilterOp , value : any ) : Query<T>
firebase.store().collection("mycollection").where("views", ">=", 3000) // Query 반환
where 절로 반환되는 데이터 타입은 Query이고, 아래와 같은 메서드를 적용할 수 있습니다. 그냥 get() 때려서 정보 가져와도 되고, 다시 where로 잡아도 됩니다.
Observe with snapshot
CollectionReference의 onSnapshot
https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference#onsnapshot
CollectionReference의 onSnapshot 메서드는 Observer를 통해 reactive하게 구현하는데 좋습니다.
onSnapshot(
onNext: (snapshot: QuerySnapshot<T>) => void,
onError?: (error: FirestoreError) => void,
onCompletion?: () => void
): () => void;
컬렉션을 Observe하다가 바뀌면, 해당 스냅샷을 가지고 도큐먼트를 출력하는 함수입니다.
firebase.firestore().collection("books").onSnapshot((QuerySnapshot) => {
QuerySnapshot?.docs.map(doc => console.log(doc));
}
인덱싱에 대해서
where, orderBy 등 Query를 다루다보면 index를 설정하란 경고가 출력됩니다.
firestore는 근본적으로 noSQL이라서 그런지, mongoDB의 인덱싱과 비슷한 부분이 있습니다.
예를 들어, firestore의 인덱스는 단일 인덱스와 복합 인덱스로 나뉩니다.
firestore의 좋은 점은 직접 인덱싱을 해줄 수도 있지만, 쿼리를 짜면 알아서 적절하게 인덱스를 구성하게끔 해준다.
콘솔창을 켜보면 쿼리가 필요하다고하고, 아래 링크를 누르면 자동으로 firestore 상의 쿼리를 생성하게 됩니다. 매우 꿀 ㅇㅇ
보안 정책에 대해서
ref)
https://firebase.google.com/docs/rules/get-started?authuser=0
이후에 보안 정책을 별도의 파트에서 다루겠습니다.