Param не перешел на локальную функцию в облачных функциях Firebase - PullRequest
0 голосов
/ 01 марта 2020

У меня есть функция облачной базы firebase:

exports.foo = functions.database
  .ref("/candidates/{jobTrack}/{candidateId}")
  .onCreate((snap, context) => {
    const candidate = snap.val().candidate;
    const jobTrack = context.params.jobTrack;

    const jobsRef = admin.database().ref("jobs");
    return jobsRef
      .child(jobTrack)
      .once("value")
      .then(jobs => {
        const promises = [];

        jobs.forEach(job => {
          promises.push(job.val());
        });

        return Promise.all(promises);
      })
      .then(jobs => {
        return jobs.forEach(job => {
          var percent = getMatchedPercent(candidate, job);
          if (percent >= 0.9) {
            admin
              .database()
              .ref("feeds")
              .child(job.feedId)
              .child("upcomingWeek")
              .push(candidate); // add to team's feed
          }
        });
      })
      .catch(err => {
        console.log("firebase got an error: ", err);
      });
  });

В функции foo я вызываю локальную не облачную функцию getMatchedPercent, которая определена следующим образом:

const getMatchedPercent = (candidate, job) => {
  console.log("In get percent: ", candidate, job);
  // do something
};

Проблема в том, что когда я проверил job.val() в foo перед вызовом getMatchedPercent, я вижу, что из консоли выводятся действительные данные для job.val(). Когда однажды попал в getMatchedPercent, я попытался напечатать job, он жалуется, что это undefined.

Есть ли что-то, что я пропустил? Почему информация job может быть потеряна при вызове функции? Спасибо!

1 Ответ

1 голос
/ 01 марта 2020

Ваша проблема вызвана следующими строками:

const promises = [];

jobs.forEach(job => {
  promises.push(job.val());
});

return Promise.all(promises);

job.val() возвращает объект (данных), а не обещание, поэтому Promise.all() неправильно интерпретирует его как разрешенное обещание без значения. В следующем блоке кода массив jobs представляет собой массив undefined значений, а не данных, которые вы ожидали.

Чтобы исправить это, вместо этого вы должны вернуть массив значений вместо использования Promise.all().

const jobValues = [];

jobs.forEach(job => {
  jobValues.push(job.val());
});

return jobValues;

Но поскольку здесь нет асинхронной работы, вы можете сгладить свою цепочку Обещаний. Таким образом, вы будете использовать меньше памяти, потому что вам не понадобится массив, содержащий все ваши job.val() объекты одновременно.

exports.foo = functions.database
  .ref("/candidates/{jobTrack}/{candidateId}")
  .onCreate((snap, context) => {
    const candidate = snap.val().candidate;
    const jobTrack = context.params.jobTrack;

    const jobsRef = admin.database().ref("jobs");
    return jobsRef
      .child(jobTrack)
      .once("value")
      .then(jobs => {
        const promises = []; // will contain any team feed update promises

        jobs.forEach(jobSnapshot => { // This is DataSnapshot#forEach
          const job = jobSnapshot.val();
          const percent = getMatchedPercent(candidate, job);
          if (percent >= 0.9) {
            promises.push(
              admin
                .database()
                .ref("feeds")
                .child(job.feedId)
                .child("upcomingWeek")
                .push(candidate) // add to team's feed
            );
          }
        });

        return Promise.all(promises);
      })
      .catch(err => {
        console.log("Failed to update team feeds: ", err);
      });
  });

Однако, это все еще имеет другую проблему, когда некоторые каналы Обновления могут быть успешными, а другие могут завершаться с ошибкой, в результате чего база данных остается в неизвестном состоянии Поэтому вместо этого вы можете рассмотреть возможность записи в базу данных атомарно (все данные записываются или вообще ничего не пишется).

Этого можно достичь, используя:

exports.foo = functions.database
  .ref("/candidates/{jobTrack}/{candidateId}")
  .onCreate((snap, context) => {
    const candidate = snap.val().candidate;
    const jobTrack = context.params.jobTrack;

    const jobsRef = admin.database().ref("jobs");
    return jobsRef
      .child(jobTrack)
      .once("value")
      .then(jobs => {
        const pendingUpdates = {}; // "path: value" pairs to be applied to the database
        const feedsRef = admin.database().ref("feeds");

        jobs.forEach(jobSnapshot => { // This is DataSnapshot#forEach
          const job = jobSnapshot.val();
          const percent = getMatchedPercent(candidate, job);

          if (percent >= 0.9) {
            const pushId = feedsRef.push().key; // push() without arguments doesn't write anything to the database, it just generates a new reference with a push ID we can use.
            const path = job.feedId + "/upcomingWeek/" + pushId;
            pendingUpdates[path] = candidate; // queue add to team's feed
          }
        });

        // apply all updates in pendingUpdates object,
        // relative to feedsRef as an all-or-nothing operation.
        // e.g. pendingUpdates["feed001/upcomingWeek/9jksdfghsdjhn"] = "someUserId"
        //      will be written to "feeds/feed001/upcomingWeek/9jksdfghsdjhn"
        return feedsRef.update(pendingUpdates); // commit changes
      })
      .catch(err => {
        console.log("Failed to apply all feed updates: ", err);
      });
  });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...