GCP Firestore는 단일 문서를 1초에 약 한 번만 업데이트가 가능하기 때문에 1초에 여러번 업데이트해야 한다면 분산 카운터 기능을 넣는 것이 좋다.
각 카운터는 샤드로 이루어진 하위 컬렉션을 갖는다.
컬렉션은 0 ~ (N-1)개의 문서를 생성하고 업데이트 시 하나의 문서에, 읽을 때는 모든 문서를 합산하여 읽는다.
num_shards 개수만큼의 문서를 생성한다.
const num_shards = 10;
function createCounter(ref) {
var batch = db.batch();
// Initialize the counter document
batch.set(ref, { num_shards: num_shards });
// Initialize each shard with count=0
for (let i = 0; i < num_shards; i++) {
const shardRef = ref.collection('shards').doc(i.toString());
batch.set(shardRef, { count: 0 });
}
// Commit the write batch
return batch.commit();
}
0 ~ (num_shards-1) 중의 하나의 수를 가지고 와 해당 문서에 값을 업데이트 한다.
const num_shards = 10;
function incrementCounter(db, ref) {
// Select a shard of the counter at random
const shard_id = Math.floor(Math.random() * num_shards).toString();
const shard_ref = ref.collection('shards').doc(shard_id);
// Update count
return shard_ref.update("count", firebase.firestore.FieldValue.increment(1));
}
for문을 돌면서 해당 서브 콜렉션의 모든 문서의 값을 합산한다.
function getCount(ref) {
// Sum the count of each shard in the subcollection
return ref.collection('shards').get().then((snapshot) => {
let total_count = 0;
snapshot.forEach((doc) => {
total_count += doc.data().count;
});
return total_count;
});
}