HTTP-запрос облачной функции с несколькими пакетными операциями чтения и записи - PullRequest
0 голосов
/ 30 мая 2018

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

  1. Получить определенное количество документов на основе запроса.
  2. Для каждого документазапрос выполняет операцию чтения.
  3. После получения нового документа из (2) выполните некоторые операции чтения / записи (удаление из вложенной коллекции, добавление документа в другую вложенную коллекцию и обновление документа в корневой коллекции).).

Поэтому мне нужно что-то, что ожидает зацикливание (2) и (3), а затем выполняет пакетную операцию.

Ниже приведен код, который я имею намомент и вроде работает, когда я проверяю функцию локально.Однако я не могу развернуть его в Firebase, так как в нем есть ошибки, такие как «каждый потом должен возвращать обещание» и «избегать вложенных обещаний».

exports.finishEvents =  functions.https.onRequest((req, res) => {
  const eventsRef = admin.firestore().collection('events');
  var currentTime = new Date().getTime();
  var currentTimeMinus1h = currentTime - 3600000;

  console.log('----- finishEvents started -----')

  const queryRef = eventsRef.where('finished', '==', false).where('date', '<=', new Date(currentTimeMinus1h)).get().then(function(querySnapshot){
    if (querySnapshot.size > 0) {
        querySnapshot.forEach(function(doc) {

          var owner_id = doc.data().owner_id;
          var event_id = doc.id;
          console.log(owner_id, event_id);

          var userEventOwnerGoingRef = admin.firestore().collection("user_events").doc(owner_id).collection('going').doc(event_id);
          userEventOwnerGoingRef.get().then(doc2 => {
            if (!doc2.exists) {
              console.log('No such document!');
            } else {
              console.log('Document data:', doc2.data());
              var goingIds = doc.data().going_ids;
              console.log('GOING IDS', goingIds);
              var batch = admin.firestore().batch();
              for (var userId in goingIds) {
                if (goingIds.hasOwnProperty(userId)) {
                  console.log(userId + " -> " + goingIds[userId]);
                  var eventRef = admin.firestore().collection("events").doc(event_id);
                  var userEventGoingRef = admin.firestore().collection("user_events").doc(userId).collection('going').doc(doc2.id);
                  var userEventAttendedRef = admin.firestore().collection("user_events").doc(userId).collection('attended').doc(doc2.id);
                  batch.set(userEventAttendedRef, doc2.data());
                  batch.delete(userEventGoingRef)
                  if (userId == doc2.data().owner_id) batch.update(eventRef, {finished: true});
                }
              }
              batch.commit().then(function () {
                return res.status(200).send("Done.");
              });
            }
          })
         .catch(err => {
           console.log('Error getting userEventOwnerGoingRef', err);
           return res.status(200).send("Finished.");
         });
       });
    } else {
        console.log("No events found");
        return res.status(200).send("Finished.");
    }
  })
  .catch(err => {
      console.log('Error getting events', err);
      return res.status(200).send("Finished.");
  });
});

Когда я проверяю его локально, даже если задание выполнено, Я получаю сообщение об ошибке, утверждающее, что

UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Can't set headers after they are sent.

Я вижу, что отправляю результат для каждого документа исходного запроса, и мне нужно будет отправить результат только один раз, чтобы завершить функцию облака.

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

1 Ответ

0 голосов
/ 05 июня 2018

Ошибка Unhandled promise rejection возникает, когда ваша функция HTTPS отправила ответ, но забыла вернуть обещание, которое разрешается до того, как будет превышен предел времени ожидания.Это означает, что вы не возвращаете все свои обещания в функции HTTPS.Ваш код должен выглядеть примерно так:

exports.finishEvents =  functions.https.onRequest((req, res) => {
  const eventsRef = admin.firestore().collection('events')
  const currentTime = new Date().getTime()
  const currentTimeMinus1h = currentTime - 3600000

  console.log('----- finishEvents started -----')

  const queryRef = eventsRef
    .where('finished', '==', false)
    .where('date', '<=', new Date(currentTimeMinus1h))

  return queryRef.get().then((querySnapshot) => {
    // Use Promise.all with snapshot.docs.map to combine+return Promise context
    return Promise.all(querySnapshot.docs.map((doc) => {
      const owner_id = doc.get('owner_id')
      const event_id = doc.id
      console.log(owner_id, event_id)

      const userEventOwnerGoingRef = admin.firestore()
        .collection("user_events").doc(owner_id)
        .collection('going').doc(event_id)
      return userEventOwnerGoingRef.get().then((doc2) => {
        if (!doc2.exists) {
          console.log('No such document!')
          return
        } else {
          console.log('Document data:', doc2.data())
          const goingIds = doc.get('going_ids')
          console.log('GOING IDS', goingIds)
          const batch = admin.firestore().batch()
          for (const userId in goingIds) {
            if (goingIds.hasOwnProperty(userId)) {
              console.log(userId + " -> " + goingIds[userId])
              const eventRef = admin.firestore().collection("events").doc(event_id)
              const userEventGoingRef = admin.firestore()
                .collection("user_events").doc(userId).collection('going').doc(doc2.id)
              const userEventAttendedRef = admin.firestore()
                .collection("user_events").doc(userId).collection('attended').doc(doc2.id)
              batch.set(userEventAttendedRef, doc2.data())
              batch.delete(userEventGoingRef)
              if (userId == doc2.get('owner_id')) {
                batch.update(eventRef, {finished: true})
              }
            }
          }
          return batch.commit()
        }
      })
    }))
  })
  .then(() => {
    return res.status(200).send('Done.')
  })
  .catch((err) => {
    console.error(err)
    return res.status(200).send('Finished.')
  })
})

Важно принять во внимание то, что вы не выполняете ни одно из ваших обещаний.Всегда держите их под контролем, будь то добавление их в массив и ожидание их разрешения или отклонения, или возвращение их из их областей / функций.Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...