2022. 5. 26. 14:40ㆍFirebase
우선 파이어 스토어의 기본 사용법을 아직 잘 모르겠다면 이전에 올린 포스트를 보고 오시거나 파이어 스토어 공식문서를 한번 먼저 읽어 보시는 것을 추천드립니다.
보통 파이어 스토어에서 많은 양의 데이터를 추가하거나 삭제할 때 Promise.all을 사용해서 처리를 하는 경우가 많습니다.
이 경우 일괄적으로 처리한다고 생각하실 수 있지만 결국에는 파이어 스토어에 하나하나씩 작업을 요청하는 것이랑 마찬가지이기 때문에 전부 별개의 작업으로 진행됩니다.
따라서 100개의 쓰기 요청을 했는데 도중에 인터넷이 끊기면 90건의 쓰기 작업만 완료되고 나머지 10개의 작업은 실패할 수도 있습니다. 일반적인 경우 이게 문제가 되진 않지만 모든 작업이 일괄적으로 처리가 되어야 하는 경우가 있습니다. 예를 들어 회원이 글을 하나 쓰면 회원 정보 문서의 글 개수 필드를 하나 업데이트한다고 가정해보겠습니다. 여기서 회원정보가 담긴 컬렉션을 User 그리고 글 컬렉션을 Post라고 가정을 했을 때 Post에서 쓰기 요청이 1번, User에서 쓰기(수정) 요청이 1번씩 진행이 됩니다. 여기서 해당 작업들을 일괄적으로 처리하지 않으면 어떤 일이 발생할까요? 카운터 업데이트 작업을 글이 등록된 후에 진행이 되도록 나눠서 요청하면 상관없겠지만 같은 함수에서 요청을 한다면 일시적인 오류로 인해 글이 등록되지 않았음에도 불구하고 User 문서의 글 개수 카운터만 변경이 될 수가 있습니다.
이런 불상사를 방지할 수 있도록 파이어 스토어에서는 데이터를 일괄적으로 쓰거나 삭제할 수 있는 Batched Processing(일괄 작업 처리)을 지원합니다.
set(), update(), delete()
일괄 작업을 진행하기 위해 파이어 스토어의 writeBatch 메서드를 통해 일괄 작업 처리를 할 수 있는 batch객체를 선언한 뒤, 처리할 작업(set, update 또는 delete) 들을 명시한 후 commit 메소드로로 일괄처리가 되도록 요청을 할 수가 있습니다.
아래 코드는 웹 알림에서 전체 읽기 버튼을 클릭했을 때 모든 알림을 읽음 표시를 업데이트해주기 위해 작성한 코드입니다. 작성된 코드는 파이어 스토어의 모듈 버전 (웹 버전 9)을 사용하고 있기 때문에 이전 방식은 파이어 스토어의 공식문서를 참고해주시길 바랍니다.
import { db } from "fb/init";
import {
doc,
writeBatch,
} from "firebase/firestore";
const markAllRead = async (notifications) => {
try {
const batch = writeBatch(db);
notifications
.filter((noti) => {
return !noti.isRead;
})
.forEach((noti) => {
const docRef = doc(db, "users", uid, "notification", noti.id);
batch.update(docRef, { isRead: true }); // 일괄적으로 수정할 작업들 대기 시키기 commit하기 전까지 실행 되지 않음
});
await batch.commit(); // 대기 시킨 작업들 일괄적으로 실행
} catch (err) {
console.log(err);
}
};
보시는 바와 같이 보통 데이터를 수정하는 거와 크게 차이가 없습니다. 일괄적으로 처리할 수정 작업들을 update 메서드로 대기시킨 뒤 마지막에 commit 메서드를 실행하게 되면 여러 번 나눠서 요청하지 않고 한 작업으로 인식하여 파이어 스토어에 요청하게 됩니다. 그렇기 때문에 도중에 한 문서라도 업데이트에 실패하게 되면 전체 실패로 간주하고 어떠한 문서도 수정하지 않습니다. 위에서는 수정 작업을 진행했지만, 추가 (set) 또는 삭제 (delete) 작업도 동일하게 진행하실 수 있습니다. 또 위 예제에서는 하나의 문서를 대상으로 일괄 작업을 진행했지만 여러 개의 문서에 대한 일괄 처리도 가능합니다. 예를 들어 알림 문서만 업데이트하는 게 아니고 사용자 문서까지 업데이트를 해야 한다면 forEach 고차 함수 부분을 아래와 같이 작성해주시고 마지막에 동일하게 commit만 해주시면 됩니다.
const docRef = doc(db, "users", uid, "notification", noti.id);
const userRef = doc(db, "users", uid)
batch.update(docRef, { isRead: true });
batch.update(userRef, { hasRead: true });
사실 위와 같은 상황에서는 일괄적으로 처리를 해주지 않아도 크게 상관이 없었을 겁니다. 그래도 사용자는 분명히 전체 읽음 표시를 할 의도로 클릭을 했는데 몇 개의 알림만 읽음 표시가 된다면 사용하는 입장에서 혼란스러울 수도 있다고 생각했기 때문에 일괄적 처리를 사용하게 된 케이스입니다.
대부분의 경우 해당 수치를 넘길 일은 없겠지만 현재 일괄처리는 최대 500개의 문서까지 가능하기 때문에 이 점 주의하시고 사용하시면 되겠습니다.
참고 자료
https://firebase.google.com/docs/firestore/manage-data/transactions
'Firebase' 카테고리의 다른 글
[Firebase 웹] 파이어스토어 검색 기능 구현하기(feat. 쿼리문 & Algolia) (6) | 2022.06.19 |
---|---|
[Firebase] 파이어스토어 페이지네이션 + 무한 스크롤 구현하기 (feat. React) (8) | 2022.06.07 |
[Firebase 웹] Cloud Function으로 RESTful API 만들기 (feat. Express) (2) | 2022.03.27 |
[Firebase 웹] 지정된 시간마다 Cloud Function 직접 호출 (2) | 2022.03.06 |
[Firebase 웹] Cloud Function 으로 파이어스토어 컬렉션과 문서 변화 (추가, 업데이트, 삭제) 감지 (0) | 2022.03.03 |