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

KSa*_*mra 1 firebase google-cloud-functions google-cloud-firestore

因此,我正在尝试为我的应用程序实现新的云功能,但需要对现有数据库数据模型进行一些调整。我数据库中的每个用户都有一个我要每周更新的字段。我不希望此功能每周都为所有用户运行,因为这将是不必要的昂贵操作。相反,我只是决定通过在用户文档中存储“最后更新”字段来跟踪我上次更新该用户的时间。

问题是我现有的400多个用户中没有一个拥有此字段。因此,我正在寻找一种为数据库中所有现有用户添加此字段的方法,该字段已初始化为某个默认时间。

我曾考虑过按如下所述使用“批量写入”:https : //firebase.google.com/docs/firestore/manage-data/transactions#batched-writes

但似乎您需要指定要更新的每个文档的ID。我所有的用户都有一个由Firestore生成的UUID,因此手动写入每个用户对我来说并不实际。有什么办法可以在现有集合的每个文档中创建一个新字段?或者,也许不是一种获取所有文档ID的列表的方法,以便我可以遍历它并进行非常丑陋的批写?我只需要执行一次此大规模更新,然后再也不需要执行一次。除非我发现一条新数据,否则我想跟踪。

Ren*_*nec 5

您可以使用一个Cloud Function:例如,您会在下面找到一个Cloud Function的代码,该代码将通过在名为的集合中创建一个文档batchUpdateTrigger来触发(请注意,这只是触发Cloud Function的一种方式。您可以很好地使用HTTPS云功能)。

在此Cloud Function中,我们以命名的集合的所有文档为基础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);

        });

  });
Run Code Online (Sandbox Code Playgroud)

您在这里可能会遇到的一个问题是您达到了Cloud Function的超时。默认超时为60秒,但是您可以在Google Cloud控制台(https://console.cloud.google.com/functions/list?project=xxxxxxx)上增加超时时间


如您所说,另一种方法是使用批处理write

然后,云功能将如下所示:

 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();

        });

  });
Run Code Online (Sandbox Code Playgroud)

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

下面是一种可能的简单方法(即不是很复杂...)。由于您将只设置一次默认值,并且只有几百个文档需要处理,我们可以认为它是可以接受的!以下Cloud Function将按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;
            }
        });
  });
Run Code Online (Sandbox Code Playgroud)

后一种技术的优势在于,如果遇到云功能超时的一些问题,则可以减小批处理的大小。