NodeJS 如何在firestore数据库中使用cloud函数更新多个文档?

xdnvmnnf  于 2023-03-17  发布在  Node.js
关注(0)|答案(1)|浏览(110)

我是firebase云函数的新手,当users集合更改了某个文档的username字段时,我想更新posts集合中某些文档的username字段,我使用以下代码来完成此操作:

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

这段代码运行良好。posts集合中的用户名更改正确。但是,一段时间后,云函数日志显示以下日志:Function execution took 60002 ms, finished with status: 'timeout'。如何解决这个问题?如果我必须更新posts集合中的数百万个文档,这个函数会有问题吗?

wydwbb8l

wydwbb8l1#

问题源于您没有返回update()方法返回的Promise,因此云函数没有被告知工作已完成,并且运行到超时。
还可能发生的是,如果你必须更新“posts集合中的数百万个文档”,云函数在你的更新全部完成之前就结束了,这更烦人!
我建议您观看Firebase video series中名为“学习JavaScript承诺”的3个视频,其中解释了返回后台触发函数的承诺的关键点。
下面的代码应该可以工作。注意,我使用了一个批处理写,它特别专用于多个写操作。

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

请注意,批处理写入最多可以包含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;
        }
    });

相关问题