Как обновить несколько документов из облачной функции в базе данных Firestore? - PullRequest
0 голосов
/ 03 октября 2019

Я новичок в облачных функциях Firebase и хочу обновить поле username некоторых документов из коллекции posts, когда коллекция users изменит это поле 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?

1 Ответ

4 голосов
/ 03 октября 2019

Проблема заключается в том, что вы не возвращаете обещание, возвращенное методом update(), поэтому облачная функция не информируется о том, что работа выполнена, и выполняется до истечения времени ожидания.

ЧтоТакже может произойти, если вам нужно обновить «миллионы документов в posts коллекции», если облачная функция завершает работу до , все ваши обновления завершены. Это еще более раздражает!

Я бы посоветовал вам посмотреть 3 видеофильма под названием «Изучите обещания JavaScript» из серии видеороликов Firebase , которые объясняют эту ключевую точку возврата обещаний для функций, запускаемых в фоновом режиме.

Следующий код должен работать. Обратите внимание, что я использовал пакетную запись , которая специально предназначена для нескольких операций записи.

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;
        }
    });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...