如何使用批处理在Firestore中更新500多个文档?

Utk*_*rsh 3 firebase firebase-admin google-cloud-firestore

我正在尝试使用包含500多个文档的集合中timestampFirestoreadmin时间戳更新字段。

const batch = db.batch();
const serverTimestamp = admin.firestore.FieldValue.serverTimestamp();

db
  .collection('My Collection')
  .get()
  .then((docs) => {
    serverTimestamp,
  }, {
    merge: true,
  })
  .then(() => res.send('All docs updated'))
  .catch(console.error);
Run Code Online (Sandbox Code Playgroud)

这引发一个错误

{ Error: 3 INVALID_ARGUMENT: cannot write more than 500 entities in a single call
    at Object.exports.createStatusError (C:\Users\Growthfile\Desktop\cf-test\functions\node_modules\grpc\src\common.js:87:15)
    at Object.onReceiveStatus (C:\Users\Growthfile\Desktop\cf-test\functions\node_modules\grpc\src\client_interceptors.js:1188:28)
    at InterceptingListener._callNext (C:\Users\Growthfile\Desktop\cf-test\functions\node_modules\grpc\src\client_interceptors.js:564:42)
    at InterceptingListener.onReceiveStatus (C:\Users\Growthfile\Desktop\cf-test\functions\node_modules\grpc\src\client_interceptors.js:614:8)
    at callback (C:\Users\Growthfile\Desktop\cf-test\functions\node_modules\grpc\src\client_interceptors.js:841:24)
  code: 3,
  metadata: Metadata { _internal_repr: {} },
  details: 'cannot write more than 500 entities in a single call' }
Run Code Online (Sandbox Code Playgroud)

有没有一种方法可以编写一个递归方法,该方法创建一个批处理对象,逐个更新一批500个文档,直到所有文档都更新。

从文档中,我知道使用递归方法可以实现删除操作,如下所述:

https://firebase.google.com/docs/firestore/manage-data/delete-data#collections

但是,对于更新,由于文档未删除,我不确定如何结束执行。

ern*_*ton 18

我喜欢这个简单的解决方案:

const users = await db.collection('users').get()

const batches = _.chunk(users.docs, 500).map(userDocs => {
    const batch = db.batch()
    userDocs.forEach(doc => {
        batch.set(doc.ref, { field: 'myNewValue' }, { merge: true })
    })
    return batch.commit()
})

await Promise.all(batches)
Run Code Online (Sandbox Code Playgroud)

只记得import * as _ from "lodash"在顶部添加。基于这个答案

  • 这应该是官方文档的一部分。或者至少是类似的东西,不依赖 lodash。奇迹般有效!:) (2认同)

Seb*_*ebe 11

我还遇到了在Firestore集合中更新500多个文档的问题。我想分享我如何解决这个问题。

我使用云功能在Firestore中更新我的收藏集,但这也可以在客户端代码上使用。

该解决方案计算对批次进行的每个操作,并在达到限制后创建新批次并将其推送到batchArray

完成所有更新后,代码循环遍历batchArray并提交阵列内的每个批处理。

它是计算每一个操作很重要 set(), update(), delete()这是批量做,因为他们都算到500的操作极限。

const documentSnapshotArray = await firestore.collection('my-collection').get();

const batchArray = [];
batchArray.push(firestore.batch());
let operationCounter = 0;
let batchIndex = 0;

documentSnapshotArray.forEach(documentSnapshot => {
    const documentData = documentSnapshot.data();

    // update document data here...

    batchArray[batchIndex].update(documentSnapshot.ref, documentData);
    operationCounter++;

    if (operationCounter === 499) {
      batchArray.push(firestore.batch());
      batchIndex++;
      operationCounter = 0;
    }
});

batchArray.forEach(async batch => await batch.commit());

return;
Run Code Online (Sandbox Code Playgroud)

  • 如何确保所有批次均成功执行,因为只有批次内的操作是原子的。如果有的批次执行,有的批次没有执行,就会导致数据不一致 (6认同)

Mix*_*OID 8

您可以使用默认的BulkWriter。该方法使用500/50/5规则。

例子:

let bulkWriter = firestore.bulkWriter();

bulkWriter.create(documentRef, {foo: 'bar'});
bulkWriter.update(documentRef2, {foo: 'bar'});
bulkWriter.delete(documentRef3);
await close().then(() => {
  console.log('Executed all writes');
});
Run Code Online (Sandbox Code Playgroud)


Fre*_*ooc 5

自 2023 年 3 月起,Firestore 不再限制可传递给 Commit 操作或在事务中执行的写入次数(来源)。