[英]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:最后两句:
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.newuserinfo
.newuserinfo
相同。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.