Firestore runTransaction()和离线工作 [英] Firestore runTransaction() and offline work

查看:104
本文介绍了Firestore runTransaction()和离线工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用事务在Firestore中实现帖子喜欢和评论功能.我使用事务处理是因为我需要在喜欢/评论"子集合中添加新字段并更新帖子的计数器,还需要将帖子ID添加到用户喜欢/评论"的帖子集合中.

I'm implementing post liking and commenting functionality in Firestore using transactions. I use transaction because I need to add new field in likes/comments subcollection and update counter on the post, and also add post id to the user liked/commented post collection.

我注意到,如果我处于离线状态,并且这样请求我的帖子,一切正常:

I noticed that if I'm offline and I request my post like this everything is OK:

val postDocRef = FirebaseUtil.postsColRef.document(postId)

postDocRef.get().addOnSuccessListener { doc ->
    val post = doc.toObject(Post::class.java)
    Timber.e(post.toString())
}

但是,如果我在事务处理中执行相同操作,则会抛出异常:

But if I do the same in transaction exception is thrown:

val postDocRef = FirebaseUtil.postsColRef.document(postId)

FirebaseUtil.firestore.runTransaction(Transaction.Function<Void> { transaction ->
    val post = transaction.get(postDocRef).toObject(Post::class.java)
}

例外是:

com.google.firebase.firestore.FirebaseFirestoreException:不可用

com.google.firebase.firestore.FirebaseFirestoreException: UNAVAILABLE

为什么脱机模式在事务中不起作用?是否可以离线实现此功能(在子集合中添加条目并更新不同对象中的字段)?

Why offline mode is not working in transaction? Is it possible to implement this functionality (adding entry in subcollection and updating fields in different objects) in offline?

continueWithTask()调用链替换事务可能有什么弊端?

What could be drawbacks in replacing transaction with continueWithTask() call chain?

推荐答案

否,这对于事务是不可能的,因为它们本质上是依赖于网络的.使用事务时,您告诉Firestore您只能同步执行数据库操作,一个客户端接一个客户端.交易对于诸如游戏中货币转移之类的事情很有用,您需要确保交易不会意外加倍并为用户提供太多或太少的钱.

No, this isn't possible with transactions because they are inherently network dependent. When you use a transaction, you are telling Firestore that you can only perform database operations synchronously, one client after the other. Transactions would be useful for stuff like in-game currency transfers where you need to ensure you don't accidentally double up your writes and give a user too much or too little money.

如果您喜欢的计数器需要具有完美的精度,我建议使用一个子集合,其中每个文档都包含对喜欢给定帖子的用户的引用.然后,在Cloud Function中,您可以使用事务来计算喜欢帖子的用户数量,并确保没有错误计数.这样做还有一个好处,那就是让您知道谁喜欢这篇帖子,如果您决定添加更多类似的功能,那么这些信息可以为将来提供证明.在客户端,即使您没有权限,也可以通过写给柜台来欺骗"它.我尚未对此进行测试,但是我很确定写入将在本地成功,然后仅在您重新联机后才会失败.但这没关系,因为云功能随后将同步计数器服务器端.

If your like counter needs to have perfect precision, I would suggest using a subcollection where each document contains a reference to the user who liked a given post. Then, in a Cloud Function you can use a transaction to count the number of users who've like a post and ensure there are no miscounts. This has the added benefit of letting you know who liked a post which should be future proof if you decided to add more like related features. On the client side, you can "trick" it by writing to the counter even though you don't have permission to do so. I haven't tested this, but I'm pretty sure the write will succeed locally and then fail only once you're back online. That doesn't matter though because the Cloud Function will then sync the counter server side.

另一方面,如果您真的不关心超精确计数,那么您要寻找的是WriteBatch类.这是Firestore中的新功能,非常酷.我正在撰写我写的关于Firestore的文章,但是下面是摘录:

On the other hand, if you don't really care about having super precise like counts, what you're looking for is the WriteBatch class. This one is new in Firestore and really cool. I'm in the process of getting a post on Firestore I wrote published, but here's an excerpt:

Cloud Firestore还提供了一种很棒的新方式来批量写入 WriteBatch类.这与 SharedPreferences.Editor在Android上可以找到.您可以添加或更新 WriteBatch实例中的文档,但它们对于 您的应用程序,直到您调用WriteBatch#commit().我已经创建了标准 Kotlin的改进,可为您管理批处理生命周期 免费访问 copypasta .

Cloud Firestore also includes an awesome new way to batch writes with the WriteBatch class. It’s very similar to the SharedPreferences.Editor you’ll find on Android. You can add or update documents in the WriteBatch instance, but they won’t be visible to your app until you call WriteBatch#commit(). I’ve created the standard Kotlin improvement where the batch lifecycle is managed for you — feel free to copypasta.

inline fun firestoreBatch(transaction: WriteBatch.() -> Unit): Task<Void> = FirebaseFirestore.getInstance().batch().run {
    transaction()
    commit()
}

这篇关于Firestore runTransaction()和离线工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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