具有多个批处理的Cloud Function http请求写 [英] Cloud Function http request with multiple batch read & writes

查看:102
本文介绍了具有多个批处理的Cloud Function http请求写的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个由http请求触发的云功能,该功能旨在执行以下操作:

I have a cloud function triggered by an http request which intends to do the following:

  1. 根据查询获取一定数量的文档.
  2. 对于查询的每个文档,执行读取操作.
  3. 从(2)获取新文档后,执行一些读/写操作(从一个子集合中删除,将该文档添加到另一个子集合中,并在根集合上更新一个文档).

因此,我需要一些东西等待(2)和(3)的循环,然后执行批处理操作.

Therefore I need something that waits for the looping of (2) and (3) and then performs a batch operation.

下面是我目前拥有的代码,当我在本地测试该功能时,这种代码可以正常工作.但是,我无法将其部署到Firebase,因为它具有承诺错误,例如每个人都必须返回一个承诺"和避免嵌套承诺".

Below is the code that I have at the moment and is kind of working when I test the function locally. However I cannot deploy it to Firebase since it has promises errors such as "every then must return a promise" and "avoid nesting promises".

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

当我在本地测试时,即使工作已完成,我也会收到一条错误消息,指出这一点

When I test it locally, even though the job is completed, I get an error stating that

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

我看到我正在为原始查询的每个文档发送结果,并且只需要发送一次结果即可完成云功能.

I can see that I am sending the result for each document of the original query, and I would only need to send the result once to finish the cloud function.

我想我需要退还诺言,然后在完成步骤(2)和(3)之后执行我的所有事务的批处理.但是,这是我第一次使用javascript,并且为此感到吃力.任何帮助将不胜感激.

I guess I need to return promises and then after steps (2) and (3) are completed perform my batch transaction of everything. However is the first time I am using javascript and I am struggling with this. Any help would be appreciated.

推荐答案

当您的HTTPS函数已发送响应但忘记返回在达到超时限制之前解析的Promise时,会遇到Unhandled promise rejection错误.这意味着您不会在HTTPS函数中返回所有诺言.您的代码应如下所示:

The Unhandled promise rejection error is encountered when your HTTPS function has sent a response but forgot to return a promise that resolves before the timeout limit has been reached. This means that you aren't returning all of your promises in the HTTPS function. Your code should look something like this:

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.')
  })
})

重要的是不要放弃您的任何诺言.无论是通过将它们添加到数组中并等待它们全部解析/拒绝,还是通过从它们的作用域/函数返回它们,始终要对它们进行处理.我希望这会有所帮助.

The important thing to take from this is to not strand any of your promises. Always keep a handle on them whether it be by adding them to an array and waiting for them all to resolve/reject, or by returning them from their scopes/functions. I hope this helps.

这篇关于具有多个批处理的Cloud Function http请求写的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆