当前位置: 首页 > 知识库问答 >
问题:

Firebase云功能:交易功能不返回promise?

司马振国
2023-03-14

下面是我正在尝试使用firebase云功能所做的事情:

-监听“用户”集合下的文档中的任何更改。

-更新“评论”和“发布”集合中相关文档中用户信息的副本。

因为我将需要在相关文档中进行查询并立即更新,所以我正在编写事务操作的代码。

这是我写的代码。它返回错误消息“Function returned undefined,expected Promise or value”。

exports.useInfoUpdate = functions.firestore.document('user/{userid}').onUpdate((change,context) => {
   const olduserinfo=change.before.data();
   const newuserinfo=change.after.data();
       db.runTransaction(t=>{
         return t.get(db.collection('comment').where('userinfo','==',olduserinfo))
        .then((querysnapshot)=>{
          querysnapshot.forEach((doc)=>{
             doc.ref.update({userinfo:newuserinfo})
          })
        })    
      })
  .then(()=>{
    db.runTransaction(t=>{
         return t.get(db.collection('post').where('userinfo','==',olduserinfo))
        .then((querysnapshot)=>{
          querysnapshot.forEach((doc)=>{
             doc.ref.update({userinfo:newuserinfo})
          })
        })    
      })
  })
});

我有点困惑,因为据我所知,'update'方法返回一个承诺?我可能错过了一些重要的东西,但我是去年11月才开始编程的,所以不要太苛刻。:)

有什么建议可以解决这个问题吗?谢谢!

编辑:基于Renaud的出色回答,我创建了下面的代码,以防有人可能需要它。事务处理的复杂之处在于,相同的数据可能以不同的索引或不同的格式存储。例如,相同的“map”变量可以存储在一个集合的索引下,而在另一个集合中作为数组的一部分。在这种情况下,查询返回的每个文档都需要不同的更新方法。

我使用doc.ref.path、split和switch方法解决了这个问题。这允许根据集合名称应用不同的更新方法。简单来说,就是这样的东西:

 return db.runTransaction(t => {
        return t.getAll(...refs)
            .then(docs => {
                docs.forEach(doc => {
                    switch (doc.ref.path.split('/')[0]) { //This returns the collection name and switch method assigns a relevant operation to be done.
                      case 'A':
                        t = t.update(doc.ref, **do whatever is needed for this collection**)
                        break;
                      case 'B':
                        t = t.update(doc.ref, **do whatever is needed for this collection**)
                        break;
                      default:
                        t = t.update(doc.ref, **do whatever is needed for this collection**)
                    }
                })
            })
    })

希望这有帮助!

共有1个答案

颛孙轩昂
2023-03-14

序言:这是一个非常有趣的用例!!

错误消息标识的问题来自这样一个事实,即您没有返回runtransaction()方法返回的承诺。但是,您的代码中还有其他几个问题。

使用node.js服务器SDK,您确实可以向事务的get()方法传递查询(使用JavaScript SDK则不行)。但是,在您的情况下,您希望更新由两个查询返回的文档。您不能两次调用db.runtransaction(),因为它不再是唯一的事务。

因此您需要通过传递一个未打包的DocumentReferences数组来使用getAll()方法。(再次注意,这个getAll()方法仅在node.js服务器SDK中可用,而在JavaScript SDK中不可用)。

下面的代码将完成这一任务。

我们运行这两个查询,并将结果转换为documentreferences的一个数组。然后我们调用runtransaction()方法,使用spread运算符解压缩documentreferences的数组,并将其传递给getAll()方法。

然后,我们循环这些文档,并将调用链接到事务的update()方法,因为它返回事务。

但是,请注意,使用这种方法,如果两个原始查询之一的结果在事务期间发生更改,则事务将看不到任何新的或删除的文档。

exports.useInfoUpdate = functions.firestore.document('user/{userid}').onUpdate((change, context) => {
    const olduserinfo = change.before.data();
    const newuserinfo = change.after.data();

    const db = admin.firestore();

    const q1 = db.collection('comment').where('userinfo', '==', olduserinfo);  // See the remark below: you probably need to use a document field here (e.g. olduserinfo.userinfo)
    const q2 = db.collection('post').where('userinfo', '==', olduserinfo);


    return Promise.all([q1.get(), q2.get()])
        .then(results => {
            refs = [];
            results.forEach(querySnapshot => {
                querySnapshot.forEach(documentSnapshot => {
                    refs.push(documentSnapshot.ref);
                })
            });


            return db.runTransaction(t => {
                return t.getAll(...refs)
                    .then(docs => {
                        docs.forEach(doc => {
                            t = t.update(doc.ref, { userinfo: newuserinfo })
                        })
                    })
            })

        })
});

最后两句话:

  1. 我不确定db.collection('comment').where('userinfo','==',olduserinfo);是否有效,因为olduserinfo是通过change.before.data()获得的。您可能需要指定一个字段。对于newuserinfo
  2. 来说,这可能是相同的
  3. 注意,您不能在事务中执行doc.ref.update(),您需要调用事务的update()方法,而不是DocumentReference的方法。
 类似资料:
  • 在研究了Firebase文档、视频、StackOverflow、大量文章之后。。。以“简单”的方式组织多个(大量)云功能并不明显。特别是,由于Firebase官方文件没有提供明确的愿景/建议。实际上,真正的问题是缺乏关于如何从一开始就建立一个具有很多功能的Firebase项目的清晰文档。 考虑到以下几点,我试图找到一种简单的方法: 基于Firebase文档(每个Firebase新用户都在阅读) 只

  • 问题内容: 尝试使用PayPal-node-SDK向Paypal的API请求 但我不断出错: 我尝试过的事情: 向完全不同的主机发出请求 将请求包装为 预先考虑到主机 问题是什么? 问题答案: 您需要按照付费计划进行外部API请求。 Firebase的Blaze计划(随用随付)为云功能免费分配。https://firebase.google.com/pricing/

  • 问题内容: 我们正在开发使用新的Firebase云功能的应用程序。当前正在发生的事情是将事务放入队列节点中。然后函数删除该节点并将其放入正确的节点。由于能够脱机工作,因此已经实现了该功能。 我们当前的问题是功能的速度。该函数本身大约需要400毫秒,所以没关系。但是有时该功能需要很长时间(大约8秒),而该条目已被添加到队列中。 我们怀疑服务器需要花费一些时间来启动,因为在第一个操作之后我们再次执行该

  • 我知道这里已经有人问过这个问题,但它没有回答我的问题。我的问题是,我们怎样才能分解指数。js用于云函数,包括onWrite调用等。 我意识到您可以使用“要求”并引入外部代码。它仍然留下一些代码(例如,在Franks OCR示例中),在index.js. 理想情况下,我希望能够将整个onWrite事件触发器移动到另一个文件中。 索引中的示例。js: 如何将整个函数event watch/call移动

  • 函数也可以将值与控件一起返回给调用者。 这些函数称为returning functions 。 语法 (Syntax) return_type function_name(){ //statements return value; } return_type可以是任何有效的数据类型。 return语句是可选的。 我没有指定函数返回null; 返回值的数据类型必须与函数的返

  • 问题内容: 我正在使用Android上的Firebase Cloud Functions库,并用于调用云函数。 问题在于该函数需要10到15秒的时间才能将结果返回给客户端,因此客户端会抛出异常。 码 如何更改超时,以便客户端在引发异常之前会等待更多时间? 注意。 我没有使用OkHttp,Retrofit或默认的系统网络功能,而是在使用Firebase Cloud Functions库()来调用该函