这是更新Firestore集合中所有文档的最佳方式吗



有类似的问题和答案,但似乎都不关心在整个集合上迭代时的并发性或使用事务。

为了确保我不会阅读一个版本的文档,更新它,然后删除自阅读以来发生的一些更改,我想使用事务。

Firestore事务限制为500个更新。

我的方法是使用分页,一次获得500个文档引用。然后在事务中使用那些具有getAll的refs,以确保不会发生并发修改。

像这样通过500名裁判获得全部进球可以/明智吗?从性能和成本的角度来看,这种方法有效吗?

伪代码(类似TypeScript(

const pageSize = 500;
let lastSnapshot = null;
let count = 0;
do {
// Get up to 500 (pageSize) document references
let query = firestore.collection('myCollection').limit(pageSize);
if (lastSnapshot) {
myDataQuery = myDataQuery.startAfter(lastSnapshot);
}
const snapshots = await playerPlotQuery.get();
const refs = snapshots.docs.map(d => d.ref);
// Start a transaction
await firestore.runTransaction(async transaction => {
// Get all the documents again, this time in a transaction
const snapshots = await transaction.getAll(...refs);
for (const snapshot of snapshots) {
// Perform some update on each document
transaction.update(snapshot.ref,{someField: 0, anotherField: "foo"});
}
});
} while (refs.length === pageSize);

因为您正在使用Transaction#getAll(),所以我假设您正在使用Firestore的Node客户端。这意味着您可以访问Transaction#get(),并且可以直接在事务内部执行查询。仅此更改就可以将您的文档读取量减半,因为您不再检查它们两次。

const pageSize = 500;
const baseQuery = db.collection('myCollection').limit(pageSize); // highly recommend using orderBy here on something like a 'creationTime' property
let totalCount = 0, pageCount = 0;
do {
const pageQuery = lastSnapshot ? baseQuery.startAfter(lastSnapshot) : baseQuery;
totalCount += pageCount = await db.runTransaction(async (transaction) => {
const querySnapshot = await transaction.get(pageQuery);
querySnapshot.forEach(docSnap => {
transaction.update(docSnap.ref, { someField: 0, anotherField: "foo" });
lastSnapshot = docSnap;
});
return querySnapshot.size; // return the page count inside the runTransaction's Promise
});
} while (pageCount === pageSize);