我正在开发一个用于清洁服务的应用程序。在此应用程序中,员工(清洁工)可以读取由多个客户(用户)完成的作业(预订)列表。
所有清洁工都可以在“用户”节点中读取所有预订。最初,当用户将预订保存在数据库中时,该键claimed:
的值为
“false”
,这意味着清洁工尚未声明该键。
每当清洁工想要索取列表中存在的工作时,他将必须触摸按钮,该按钮将向Firebase数据库发出请求以将key的值修改claimed
为true
at路径。
/Users/UID/bookings/bookingNumber
一次只能允许一名清洁工修改claimed
钥匙的价值。如果允许多个清理者修改claimed
密钥的值,其他清理者最终将要求相同的工作。我们不希望这种情况发生。
此外,在清理者将claimed
key
的值修改为之后true
,我们将需要再次请求路径CLeaners/UID/bookings/bookingNumber
,以保存他刚刚在清理者节点中声明的预订。
-根据firebase的文档,每当我们希望一次仅由一个请求修改一个资源时,便会使用事务,如果有多个并发请求试图写入同一资源,则其中一个会成功。但是使用事务的问题在于,它 只能 写入 一个路径 ,而不能写入 多个路径 。
我如何确保即使有多个用户可以读取此路径
/Users/UID/bookings/bookingNumber
,一次也只能更新一个用户?如果写入成功,则进一步写入第二条路径
Cleaners/UID/bookings/bookingNumber
。
我们需要考虑到客户端的互联网连接可能断开,用户可以退出该应用程序,或者仅仅是电话在写入上述指定路径之间的任何时间意外关闭。
数据库结构如下
Root
Cleaners
UID
bookings
bookingNumber
amount: “10”
claimed: “true”
Users
UID
otherID
bookingNumber
amount: “10”
claimed: “true”
bookingNumber
amount: “50”
claimed: “false”
为了避免任何覆盖,我决定使用Firebase事务。我可以将单个节点作为事务写入,但是在完成处理程序中写入第二个节点不是解决方案,因为在从服务器接收到响应之前,清洁程序的Internet连接可能会断开,或者应用程序可能会退出,因此,完成处理程序{(error, committed,snapshot) in....
将不会被评估,并且第二次写入将不会成功。
另一种情况是:执行第一次写入,
1.在客户端应用程序中收到响应
2. 在客户端应用程序中尚未收到响应
,用户立即退出了该应用程序。在这种情况下,将永远不会执行第二次写入,因为在完成处理程序中接收到(或未接收到)响应之后,尚未评估任何代码,因此我的数据库处于不一致状态。
从Firebase文档:
事务不会在应用程序重启后持续存在
即使启用了持久性,事务也不会在应用程序重启后持久化。因此,您不能依赖脱机完成的事务提交到Firebase实时数据库。
如果是这样,我该怎么做?我在Google https://firebase.googleblog.com/2015/09/introducing-
multi-location-updates-
and_86.html的博客中没有看到任何示例
。我确实知道您可以原子地写多个节点,但是我想以事务方式编写。我试图在else
子句中写入两个节点,但在此行收到警告let updated = updateInUsersAndCleaners as? FIRMutableData
从“ [FIRDatabaseReference:FIRMutableData]”强制转换为不相关的类型“ FIRMutableData”始终失败
class ClaimDetail: UIViewController,UITableViewDelegate,UITableViewDataSource {
var valueRetrieved = [String:AnyObject]()
var uid:String?
@IBAction func claimJob(_ sender: Any) {
dbRef.runTransactionBlock({ (_ currentData:FIRMutableData) -> FIRTransactionResult in
//if valueRetrieved is nil abort
guard let val = currentData.value as? [String : AnyObject] else {
return FIRTransactionResult.abort()
}
self.valueRetrieved = val
guard let uid = FIRAuth.auth()?.currentUser?.uid else {
return FIRTransactionResult.abort()
}
self.uid = uid
for key in self.valueRetrieved.keys {
print("key is \(key)")
//unwrap value of 'Claimed' key
guard let keyValue = self.valueRetrieved["Claimed"] as? String else {
return FIRTransactionResult.abort()
}
//check if key value is true
if keyValue == "true"{
//booking already assigned, abort
return FIRTransactionResult.abort()
} else {
//write the new values to firebase
let newData = self.createDictionary()
currentData.value = newData
let usersRef = self.dbRef.child("Users").child(FullData.finalFirebaseUserID).child(FullData.finalStripeCustomerID).child(FullData.finalBookingNumber)
let cleanersRef = self.dbRef.child("Cleaners").child(self.uid!).child("bookings").child(FullData.finalBookingNumber)
//Create data we want to update for both nodes
let updateInUsersAndCleaners = [usersRef:currentData,cleanersRef:currentData]
let updated = updateInUsersAndCleaners as? FIRMutableData
return FIRTransactionResult.success(withValue: updated!)
}//end of else
}//end of for key in self
return FIRTransactionResult.abort()
}) {(error, committed,snapshot) in
if let error = error {
//display an alert with the error, ask user to try again
self.alertText = "Booking could not be claimed, please try again."
self.alertActionTitle = "OK"
self.segueIdentifier = "unwindfromClaimDetailToClaim"
self.showAlert()
} else if committed == true {
self.alertText = "Booking claimed.Please check your calendar"
self.alertActionTitle = "OK"
self.segueIdentifier = "unwindfromClaimDetailToClaim"
self.showAlert()
}
}
}//end of claimJob button
}//end of class
extension ClaimDetail {
//show alert to user and segue to Claim tableView
func showAlert() {
let alertMessage = UIAlertController(title: "", message: self.alertText, preferredStyle: .alert)
alertMessage.addAction(UIAlertAction(title: self.alertActionTitle, style: .default, handler: { (action:UIAlertAction) in
self.performSegue(withIdentifier: self.segueIdentifier, sender: self)
}))
self.present(alertMessage, animated: true,completion: nil)
}
//create dictionary with data received from completion handler and the new data
func createDictionary() -> AnyObject {
let timeStamp = Int(Date().timeIntervalSince1970)
self.valueRetrieved["CleanerUID"] = uid as AnyObject?
self.valueRetrieved["TimeStampBookingClaimed"] = timeStamp as AnyObject?
self.valueRetrieved["Claimed"] = "true" as AnyObject?
print("line 89 extension CLaim Detail")
return self.valueRetrieved as AnyObject
}
} // end of extension ClaimDetail
在Firebase文档的“
启用脱机功能 ”部分中,指定了:
事务不会在应用程序重新启动之间
持久化即使启用了持久性,事务也不会在应用程序重新启动之间持久化。
因此,您不能依赖脱机完成的事务提交到Firebase实时数据库。
因此:
1.无法在客户端使用Firebase事务来更新两个或更多路径上的值。
2.使用完成回调执行第二次写入是不可行的,因为客户端可以在从Firebase服务器接收到完成处理程序中的响应之前重新启动应用程序,从而使数据库处于不一致状态。
我假设我唯一的选择是通过Firebase文档中指定的条件在REST上使用条件请求,以在第一路径上进行事务性更新数据,并进一步使用已在Firebase数据库中的第一路径上写入的数据来更新第二路径 。
这将实现Firebase框架为IOS客户端提供的相同功能。
什么是ETAG值?
:(唯一标识符,每次在发出GET请求的路径上数据发生更改时,标识符都会不同。即,如果另一个用户在我的写请求成功之前在同一路径上写资源,我的写操作将被拒绝因为该路径上的ETAG值将已经被其他用户的写操作修改过。这将使用户可以通过事务方式将数据写入路径)
root/Cleaners/bookings/4875383
以反映清洁工声称的工作。我有以下情况。 有一个 CQL 表 (卡桑德拉 2.0.12) 并使用datastax-java驱动程序(cassandra-driver-core 2.1.1)使用它 当集群包含3个节点时,数据更新,如 在大约一半的情况下无法静默工作(我在Cassandra日志中没有看到错误,跟踪中没有任何可疑之处,没有失败答案或异常,我可以看到它没有通过SELECT成功)。如果来自一个节点的集群,它总是有效的
我需要帮助找出使用Firebase的最佳方式。我正在制作一个twitter克隆,但与FireFeed不同,我的帖子是可变的。 我的数据库结构如下: 房间,基本上是一个你可以订阅的帖子提要。会议室成员可以向该会议室发帖: 房间/{房间ID}/帖子/{postId}/- 用户,所有用户的全局列表: 用户/{userId}/feed/{postId}- 帖子,实际帖子内容的全球列表: 贴子/{postI
firebase中我的数据库截图 这里我有一个叫做产品的节点。在那里,我有许多子节点。所有这些节点都有一个共同的值叫做产品库存。我需要更新产品内部所有节点的产品库存值。我如何在android Studio(Java)中做到这一点,因为我正在开发一个购物应用程序?需要帮助。 流程是:用户将产品添加到购物车。在购物车里,我有ordernow按钮。因此,当用户现在单击order时,应该从products
假设我的数据库结构如下: 当删除任何用户1\u UID时,我想从所有节点a、b、c中删除用户1\u UID。 例如,如果我从节点b中删除了key1:user1\u-UID,是否有一种方法也可以从节点a和节点c中删除key1:user1\u-UID,而无需遍历所有节点?还是我的数据结构错误(请注意,这些数据可能嵌套得更深)?
使用< code>node-postgres我想更新我的用户模型中的列,目前我有这个 所以我可以做到这一点 但是,如果我想更新多个列和值,我目前正在做一些非常低效的事情,并调用该方法x次(即对于每个查询) 我如何通过只调用一次数据库来生成这个。 谢谢
我使用Kafka作为队列,节点服务使用Kafka节点生成和使用Kafka主题的消息。 我一直在使用自制的分布式跟踪解决方案,但现在我们正在转向弹性APM。 这似乎是为HTTP服务器量身定制的,但如何配置它以与Kafka一起使用呢? 我希望能够像下面这样跟踪事务:服务A向服务B发送一个HTTP请求,服务B向Kafka Topic C生成该请求,服务D从中使用该请求,服务D将一些数据放入Kafka T