как да актуализирате множество документи от облачна функция в базата данни на firestore?

Аз съм нов в облачните функции на 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?


person eegooDeveloper    schedule 03.10.2019    source източник


Отговори (1)


Проблемът идва от факта, че не връщате обещанието, върнато от метода update(), следователно облачната функция не е информирана, че работата е свършена и работи до изчакване.

Това, което също може да се случи, ако трябва да актуализирате „милиони документи в колекция posts“, е облачната функция да приключи преди да са готови всичките ви актуализации. Това е по-досадно!

Предлагам ви да гледате 3-те видеоклипа, озаглавени „Научете обещанията на JavaScript“ от видеопоредицата< на Firebase /a>, които обясняват тази ключова точка за връщане на Promises за функции, задействани във фонов режим.

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

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;
        }
    });
person Renaud Tarnec    schedule 03.10.2019
comment
благодаря ти за отговора. не използвах групово записване поради този отговор stackoverflow.com/a/52170284/2923116 - person eegooDeveloper; 03.10.2019
comment
Добре, има смисъл, ако знаете, че може да имате повече от 500 документа за актуализиране. Вижте актуализацията на моя отговор в долната част. - person Renaud Tarnec; 03.10.2019