firebase 如何向数据库中的所有当前文档添加新字段?

djmepvbi  于 2023-03-19  发布在  其他
关注(0)|答案(1)|浏览(152)

因此,我尝试为我的应用程序实现一个新的云函数,但它需要对我现有的数据库数据模型做一点调整。我的数据库中的每个用户都有一个字段,我每周都要尝试更新它。我不希望每周为所有用户运行这个函数,因为这将是一个不必要的昂贵操作。相反,我决定通过存储一个“last-已更新"字段。
问题是我现有的400多个用户中没有一个有这个字段,所以我正在寻找一种方法来为数据库中的所有现有用户添加这个字段,初始化到某个默认时间。
我曾考虑过使用“批处理写入”,如下所述:https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes
但似乎您需要指定要更新的每个文档的ID。我的所有用户都有一个由Firestore生成的UUID,因此手动写入每个用户并不实际。有没有办法在现有集合的每个文档中创建新字段?如果没有,也许有办法获得所有文档ID的列表。这样我就可以迭代它并做一个非常丑陋的批量写入?我只需要做一次这种批量更新,然后再也不会了。除非我发现了一个新的数据,我想跟踪。

yrefmtwq

yrefmtwq1#

您可以使用云函数:例如,你会在下面找到一个云函数的代码,你可以通过在一个名为batchUpdateTrigger的集合中创建一个文档来触发它(注意,这只是触发云函数的一种方式,你可以使用HTTPS云函数来实现)。
在这个云函数中,我们获取名为collection的集合中的所有文档,并向每个文档添加一个新字段,其中包含当前日期/时间(ServerValue.TIMESTAMP)。我们使用Promise.all()并行执行所有更新异步工作。不要忘记向batchUpdateTrigger集合添加写访问权限,并在云函数运行后删除它。

exports.batchUpdate = functions.firestore
  .document('batchUpdateTrigger/{triggerId}')
  .onCreate((snap, context) => {

    var collecRef = db.collection('collection');
    return admin.collecRef.get()
        .then(snapshot => {

           const ts = admin.database.ServerValue.TIMESTAMP;
           var promises = [];

           snapshot.forEach(doc => {
             const ref = doc.ref;

             promises.push(
               ref.update({
                   lastUpdate: ts
               });
             );

           });

           return Promise.all(promises);

        });

  });

这里你可能会遇到的一个问题是你达到了云功能的超时时间,默认的超时时间是60秒,但是你可以在谷歌云控制台上增加它(https://console.cloud.google.com/functions/list?project=xxxxxxx
另一种方法是,如您所说,使用批量写入
云函数将如下所示:

exports.batchUpdate = functions.firestore
  .document('batchUpdateTrigger/{triggerId}')
  .onCreate((snap, context) => {

    var collecRef = db.collection('collection');
    return admin.collecRef.get()
        .then(snapshot => {

           const ts = admin.database.ServerValue.TIMESTAMP;
           let batch = db.batch();

           snapshot.forEach(doc => {
             const ref = doc.ref;

             batch.update(ref, {
                   lastUpdate: ts
               });

           });

           return batch.commit();

        });

  });

但是,您需要在代码中管理批处理中最多500个操作的限制

下面是一个可能的 * 简单 * 方法(即不是很复杂...)。由于您只设置一次默认值,并且您只有几百个文档需要处理,我们认为它是可以接受的!下面的云函数将以500个文档为一批处理文档。因此您可能需要手动重新触发它,直到所有文档都处理完毕。

exports.batchUpdate = functions.firestore
  .document('batchUpdateTrigger/{triggerId}')
  .onCreate((snap, context) => {

    var collecRef = db.collection('collection');
    return admin.collecRef.get()
        .then(snapshot => {

           const docRefsArray = [];
           snapshot.forEach(doc => {
              if (doc.data().lastUpdate == null) {
                 //We need to "treat" this doc
                 docRefsArray.push(doc.ref);
              )
            });

            console.log("Nbr of doc to treat: " + docRefsArray.length); //When the output is 0 you are done, i.e. all the docs are treated

            if (docRefsArray.length > 0) {

                const ts = admin.database.ServerValue.TIMESTAMP;

                let batch = db.batch();

                if (docRefsArray.length < 500) {

                   //We can "treat" all the documents in the QuerySnapshot
                   docRefsArray.forEach(ref => {
                      batch.update(ref, {
                         lastUpdate: ts
                      });
                   });

                } else {

                   //We need to "treat" only 500 documents
                   for (let i = 0; i < 500; i++) {
                      batch.update(docRefsArray[i], {
                         lastUpdate: ts
                      });
                }

                ​return batch.commit();

            } else {
                return null;
            }
        });
  });

最后一种技术的优点是,如果遇到云函数超时的问题,可以减小批处理的大小。

相关问题