简体   繁体   English

Firebase 云函数:事务 function 不返回 promise?

[英]Firebase Cloud Functions: Transactions function not returning promise?

here is what I am trying to do with firebase cloud function:这是我想用 firebase 云 function 做的事情:

-Listen to any change in one of the documents under 'user' collection. -收听“用户”集合下的文档之一的任何更改。

-Update carbon copies of the userinfo in the relevant documents in both 'comment' and 'post' collections. -在“评论”和“发布”collections 的相关文档中更新用户信息的副本。

Because I will need to query in relevant documents and update them at once, I am writing codes for transaction operations.因为我需要在相关文档中查询并立即更新它们,所以我正在编写事务操作的代码。

Here is the code that I wrote.这是我写的代码。 It returns the error message, 'Function returned undefined, expected Promise or value'.它返回错误消息“函数返回未定义,预期 Promise 或值”。

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

I am a bit confused because as far as I know, 'update' method returns a promise?我有点困惑,因为据我所知,“更新”方法返回 promise? I might be missing something big but I picked up programming only last November, so don't be too harsh.我可能遗漏了一些重要的东西,但我是在去年 11 月才开始编程的,所以不要太苛刻。 :) :)

Any advice on how to fix this issue?有关如何解决此问题的任何建议? Thanks!谢谢!

EDIT: Building on Renaud 's excellent answer, I created the below code in case someone may need it.编辑:Renaud的出色回答的基础上,我创建了以下代码以防有人需要它。 The complication with transaction is that the same data may be stored under different indices or in different formats.事务的复杂性在于,相同的数据可能存储在不同的索引下或以不同的格式存储。 eg The same 'map' variable can be stored under an index in one collection, and as part of an array in another.例如,相同的“地图”变量可以存储在一个集合的索引下,也可以作为另一个集合的一部分存储。 In this case, each document returned by querying needs different update methods.在这种情况下,查询返回的每个文档都需要不同的更新方法。

I resolved this issue using doc.ref.path, split, and switch methods.我使用 doc.ref.path、split 和 switch 方法解决了这个问题。 This enables application of different update methods based on the collection name.这使得可以根据集合名称应用不同的更新方法。 In a nutshell, something like this:简而言之,是这样的:

 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**)
                    }
                })
            })
    })

Hope this helps!希望这可以帮助!

Preamble: This is a very interesting use case!!序言:这是一个非常有趣的用例!!

The problem identified by the error message comes from the fact that you don't return the Promise returned by the runTransaction() method.错误消息标识的问题来自您没有返回runTransaction()方法返回的 Promise 的事实。 However there are several other problems in your code.但是,您的代码中还有其他几个问题。

With the Node.js Server SDK you can indeed pass a query to the transaction's get() method (you cannot with the JavaScript SDK).使用Node.js 服务器 SDK您确实可以将查询传递给事务的get()方法(您不能使用 JavaScript SDK)。 However, in your case you want to update the documents returned by two queries.但是,在您的情况下,您想要更新两个查询返回的文档。 You cannot call twice db.runTransaction() because, then, it is not a unique transaction anymore.您不能调用两次db.runTransaction() ,因为它不再是唯一的事务。

So you need to use the getAll() method by passing an unpacked array of DocumentReferences .因此,您需要通过传递一个未打包的DocumentReferences数组来使用getAll()方法。 (Again, note that this getAll() method is only available in the Node.js Server SDK and not in the JavaScript SDK). (再次注意,此getAll()方法仅在 Node.js 服务器 SDK 中可用,在 JavaScript SDK 中不可用)。

The following code will do the trick.下面的代码可以解决问题。

We run the two queries and transform the result in one array of DocumentReferences .我们运行这两个查询并将结果转换为一个DocumentReferences数组。 Then we call the runTransaction() method and use the spread operator to unpack the array of DocumentReferences and pass it to the getAll() method.然后我们调用runTransaction()方法并使用扩展运算符解包DocumentReferences数组并将其传递给getAll()方法。

Then we loop over the docs and we chain the calls to the transaction's update() method, since it returns the transaction.然后我们遍历文档并将调用链接到事务的update()方法,因为它返回事务。

However note that, with this approach, if the results of one of the two original queries change during the transaction, any new or removed documents will not be seen by the transaction.但是请注意,使用这种方法,如果两个原始查询之一的结果在事务期间发生更改,则事务将不会看到任何新的或删除的文档。

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

        })
});

Two last remarks:最后两句:

  1. I am not sure that db.collection('comment').where('userinfo', '==', olduserinfo);我不确定db.collection('comment').where('userinfo', '==', olduserinfo); will be valid as olduserinfo is obtained through change.before.data() .将有效,因为olduserinfo是通过change.before.data()获得的。 You probably need to specify one field.您可能需要指定一个字段。 This is probably the same for newuserinfo .这可能与newuserinfo相同。
  2. Note that you cannot do doc.ref.update() in a transaction, you need to call the transaction's update() method, not the one of a DocumentReference .请注意,您不能在事务中执行doc.ref.update() ,您需要调用事务的update()方法,而不是DocumentReference的方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在firebase云功能中返回多个异步函数的承诺? - Returning a promise of multiple async functions in a firebase cloud function? Firebase 可调用函数。 Promise 在客户端返回 null(云函数) - Firebase callable functions. Promise is returning null on the client ( Cloud Functions ) 这是在 firebase 云函数中返回 ES6 承诺的正确方法吗? - Is this the correct way of returning a ES6 promise in firebase cloud functions? 在 Firebase Cloud Functions 中使用 async/await 时返回一个 Promise - Returning a promise when using async/await in Firebase Cloud Functions 关于在 firebase 云函数中 promise 的 then 回调中返回 null 值的问题 - Question regarding returning a null value in a then callback of a promise in firebase cloud functions Firebase Cloud功能:承诺无法解决 - Firebase Cloud Functions: Promise not resolving Firebase Cloud Functions“函数返回了未定义的,预期的承诺或价值” - Firebase Cloud Functions “Function returned undefined, expected Promise or value” Firebase云函数错误-函数返回未定义,预期的承诺或价值 - Firebase cloud functions error - Function returned undefined, expected Promise or value Firebase云功能-返回的函数未定义,预期的承诺或价值 - Firebase cloud functions - Function returned undefined, expected Promise or value Firebase云函数aync / await返回未定义,导致函数崩溃 - firebase cloud functions aync/await returning undefined causing the function to crash
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM