如何从firestore数据库中的云功能更新多个文档?

eeg*_*per 4 node.js firebase google-cloud-functions google-cloud-firestore

我是 firebase 云函数的新手,我想在集合更改特定文档的字段时更新集合username中某些文档的字段。我使用以下代码来做到这一点:postsusersusername

exports.updateProfileUsername = functions.firestore
  .document('users/{userId}')
  .onUpdate((change, context) => 
  {
    const {userId} = context.params;

    var newUsername = change.after.data().username;
    var previousUsername = change.before.data().username;

    if (newUsername.localeCompare(previousUsername) !== 0)
    {
      let postCollectionRef = db.collection('posts');
      let postQuery = postCollectionRef.where('userId', '==', `${userId}`);

      return new Promise((resolve, reject) => 
      {
        updateUsernameDocuments(postQuery, reject, newUsername);
      });
    }
  });

function updateUsernameDocuments(query, reject, newValue) 
  {
    query.get()
      .then((snapshot) => 
      {
        if (snapshot.size === 0) 
        {
          return 0;
        }

        return snapshot.docs.forEach((doc) =>
        {
          doc.ref.update({username : `${newValue}`});
        });
      }).catch(reject);
  }
Run Code Online (Sandbox Code Playgroud)

这段代码工作正常。posts集合中的用户名正在正确更改。但是,一段时间后,云功能日志显示此日志:Function execution took 60002 ms, finished with status: 'timeout'。如何解决?如果我必须更新数百万个文档posts集合,这个功能会成为问题吗?

Ren*_*nec 16

问题来自于您没有返回update()方法返回的 Promise ,因此 Cloud Function 不会被告知工作已完成并运行到超时。

如果您必须更新“posts收集中的数百万个文档”,还可能发生的情况是,云功能您的更新全部完成之前结束。这更烦人!

我建议您观看 Firebase视频系列中名为“Learn JavaScript Promises”的 3 个视频,这些视频解释了为后台触发函数返回 Promise 的关键点。

以下代码应该可以工作。请注意,我使用了批处理写入,它专门用于多个写入操作。

exports.updateProfileUsername = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
        const { userId } = context.params;

        var newUsername = change.after.data().username;
        var previousUsername = change.before.data().username;

        if (newUsername.localeCompare(previousUsername) !== 0) {
            const postCollectionRef = db.collection('posts');
            const postQuery = postCollectionRef.where('userId', '==', `${userId}`);

            return postQuery.get()
                .then(querySnapshot => {

                    if (querySnapshot.empty) {
                        return null;
                    } else {
                        let batch = db.batch();

                        querySnapshot.forEach(doc => {
                            batch.update(doc.ref, { username: `${newUsername}` });
                        });

                        return batch.commit();

                    }
                });
        } else {
            return null;
        }
    });
Run Code Online (Sandbox Code Playgroud)

请注意,批量写入最多可包含 500 个操作。如果您计划更新超过 500 个文档,则可以Promise.all()改为使用,如下所示:

exports.updateProfileUsername = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
        const { userId } = context.params;

        var newUsername = change.after.data().username;
        var previousUsername = change.before.data().username;

        if (newUsername.localeCompare(previousUsername) !== 0) {
            const postCollectionRef = db.collection('posts');
            const postQuery = postCollectionRef.where('userId', '==', `${userId}`);

            return postQuery.get()
                .then(querySnapshot => {

                    if (querySnapshot.empty) {
                        return null;
                    } else {
                        const promises = []

                        querySnapshot.forEach(doc => {
                            promises.push(doc.ref.update({ username: `${newUsername}` }));
                        });

                        return Promise.all(promises);
                    }
                });
        } else {
            return null;
        }
    });
Run Code Online (Sandbox Code Playgroud)