我有一个观察函数,它显示添加到Firebase实时数据库的项目。
func observerMessages(completion: @escaping (FireBaseResponse, MessageDataModel) -> Void) {
let ref = Database.database().reference().child(FireBaseConstants.Database.messages).queryOrdered(byChild: FireBaseConstants.Database.timestamp).queryEnding(atValue: firstMessageTimestamp)
ref.observe(.childAdded) { (snapshot) in
if let dict = snapshot.value as? [String:Any] {
if let username = dict["username"] as? String,
let timestamp = dict["timestamp"] as? Int,
let text = dict["text"] as? String,
let senderId = dict["senderId"] as? String {
let message = MessageData(username: username, timestamp: timestamp, text: text, senderId: senderId, messageId: snapshot.key)
print("observeMessages")
completion(.success, message)
}
}
}
}
问题是,此函数会为数据库中已存在的所有项触发。因此,它检索该子级中的所有数据。我想让它检索数据,这些数据是在这个函数调用后添加的。
Firebase在服务器和客户端之间同步特定位置或特定查询的数据。没有内置的API只要求发送新数据。
有几种方法可以在API之上实现这一用途:
-
只将新数据存储在一个位置,并在客户端读取后将其删除。这是在Firebase上实现消息传递的常见方法:为每个客户端编写一个消息队列,并让客户端在处理数据时删除数据。
-
仅查询自客户端上次读取数据以来已写入的数据。这需要在每个子节点上都有一个
createdAt
或updatedAt
时间戳属性,并将lastReadDataAt
时间戳存储在客户端中。现在,当客户端连接时,它会运行一个按属性排序的查询,并传入上次同步的时间戳。有了这些参数,数据库将只返回自客户端上次读取以来创建/更新的数据。 -
只请求一个最近的项目。这意味着您可以按一些按时间顺序排列的键(例如
childByAutoId
生成的键(对数据进行排序,然后使用limitQuery(toLast:1)
从数据库中只请求一个最近的子节点。这样,您只能获得一个最近的子节点。虽然这在某些情况下有效,但我几乎从未使用过它,因为当客户端失去连接时,可能会错过事件。