问题
I am using the below code to retrieve the messages in a chat application according to the timestamp but it is not retrieving in order of the timestamp, How should I make sure that messages retrieved are in the order of the timestamp.
I am using Firestore database and Swift IOS for this application
below is the code parts
timestamp saved in database
let timestamp = Int(NSDate().timeIntervalSince1970)
Code to retrieve messages
let ref = Firestore.firestore().collection("messages").order(by: "timestamp", descending: true)
ref.addSnapshotListener { (snapshot, error) in
snapshot?.documentChanges.forEach({ (diff) in
let messageId = diff.document.documentID
let messageRef = Firestore.firestore().collection("messages")
.document(messageId)
messageRef.getDocument(completion: { (document, error) in
guard let dictionary = document?.data() as? [String : Any] else { return }
let message = Message(dictionary: dictionary)
print("we fetched this message \(message.text)")
self.messages.append(message)
DispatchQueue.main.async {
self.collectionView.reloadData()
let indexPath = IndexPath(item: self.messages.count - 1, section: 0)
self.collectionView.scrollToItem(at: indexPath, at: .bottom, animated: true)
}
})
})
}
回答1:
Perhaps an oversight but what's happening here is the code gets the data you want in descending order by timestamp, but then gets that same data again, which will be unordereed because it's being retrieved asynchronously, and adds to the array.
func doubleGettingData() {
let ref = Firestore.firestore()....
Gets data -> ref.addSnapshotListener { (snapshot, error) in
snapshot?.documentChanges.forEach({ (diff) in
Gets data again -> messageRef.getDocument(completion
To add a bit more context, the 'outside' function shown in the question is in fact getting the documents in the correct order. However, getting those same documents again, they are being returned from Firebase in whatever order they complete in because Firebase calls are asynchronous. This can be proven if we remove all the code except for the two calls. Here's an example Firestore Structure
message_0:
timestamp: 2
message_1
timestamp: 0
message_2
timestamp: 1
and when some print statement are added, here's what's happening
outside func gets: message_0 //timestamp 2
outside func gets: message_2 //timestamp 1
outside func gets: message_1 //timestamp 0
inside func returns: message_1 //timestamp 0
inside func returns: message_2 //timestamp 1
inside func returns: message_0 //timestamp 2
I would make a couple of changes...
Here's my Message class and the array to store the messages in
class Message {
var text = ""
var timestamp = ""
convenience init(withSnap: QueryDocumentSnapshot) {
self.init()
self.text = withSnap.get("text") as? String ?? "No message"
self.timestamp = withSnap.get("timestamp") as? String ?? "No Timestamp"
}
}
var messages = [Message]()
and then the code to read the messages, descending by timestamp and store them in the array. Note
The first query snapshot contains added events for all existing documents that match the query
func readMessages() {
let ref = Firestore.firestore().collection("messages").order(by: "timestamp", descending: true)
ref.addSnapshotListener { querySnapshot, error in
guard let snapshot = querySnapshot else {
print("Error fetching snapshots: \(error!)")
return
}
snapshot.documentChanges.forEach { diff in
if (diff.type == .added) {
let snap = diff.document
let aMessage = Message(withSnap: snap)
self.messages.append(aMessage)
}
if (diff.type == .modified) {
let docId = diff.document.documentID
//update the message with this documentID in the array
}
if (diff.type == .removed) {
let docId = diff.document.documentID
//remove the message with this documentID from the array
}
}
}
}
This code will also watch for changes and deletions in messages and pass that event to your app when they occur.
来源:https://stackoverflow.com/questions/59017647/not-able-retrieve-documents-in-chat-application-according-to-the-timestamp