For an iOS app I am working on, I need to fetch messages in descending order i.e the latest message comes first, followed by second newest message etc.
From looking at other SO answers and research it seems that the best approach for my situation is to create a negative timestamp and then persist that to the database as an extra property to messages.
I will then use queryOrderedByChild('negativeTimestamp')
to fetch the messages in a observeSingleEvent
and then have a childAdded observer to handle messages which are sent once initial calls are made.
In the firebase documentation it says I can get the server timestamp value from this snippet of code firebase.database.ServerValue.TIMESTAMP
How do I write this for Swift 3?
First, see the linked answer in the comments. That answer relies on the client to generate a timestamp that's made negative and written to Firebase.
If you want to have Firebase generate a timestamp, that can be done as well with this little snappy Firebase structure and piece of code.
First, let's take a look at the structure
root
parent_node
-Y8j8a8jsjd0adas
time_stamp: -1492030228007
timestamp: 1492030228007
Next, some code to create and work with that structure:
Define a var we can use within our class that references the Firebase time stamp
let kFirebaseServerValueTimestamp = [".sv":"timestamp"]
and a function that adds an observer to the timestamp node:
func attachObserver() {
let timestampRef = self.ref.child("timestamp")
let parentNodeRef = self.ref.child("parent_node")
var count = 0
timestampRef.observe(.value, with: { snapshot in
if snapshot.exists() {
count += 1
if count > 1 {
let ts = snapshot.value as! Int
let neg_ts = -ts
let childNodeRef = parentNodeRef.childByAutoId()
let childRef = childNodeRef.child("time_stamp")
childRef.setValue(neg_ts)
count = 0
}
}
})
And a function that writes out a timestamp, therefore causing the observer to fire which creates child nodes within the parent_node based on the Firebase time stamp
func doTimestamp() {
let timestampRef = self.ref.child("timestamp")
timestampRef.setValue(kFirebaseServerValueTimestamp)
}
Here's the rundown.
In the attachObserver function, we attach an observer to the timestamp node - that node may or may not exist but if it doesn't it will be created - read on. The code in the closure is called any time an event occurs in the timestamp node.
When the doTimestamp function is called, it creates and writes a timestamp to the timestamp node, which then fires the observer we attached in attachObserver.
The code in the observe closure does the following:
Make sure the snapshot contains something, and if it does, increment a counter (more on that in a bit). If the counter is greater than 1 get the timestamp as an integer from the snapshot. Then, create it's negative and write it back out to Firebase as a child of parent_node.
How this would apply would be anytime you want to timestamp a child node with a Firebase generated timestamp but negative value for reverse loading/sorting - which speaks to the OP question.
The gotcha here is that when this happens
timestampRef.setValue(kFirebaseServerValueTimestamp)
It actually writes twice to the node, which would cause the code in the closer to be called twice.
Maybe a Firebaser can explain that, but we need to ignore the first event and capture the second, which is the actual timestamp.
So the first event will cause the observer closer to fire, making count = 1, which will be ignored due to the if statement.
Then the second event fires, which contains the actual timestamp, and that's what we use to make negative and write out to Firebase.
Hope this helps the OP and the commenters.
Regardless whether it's for Swift or not, another conceptual solution is to rely on Firebase's server time offset value.
It's not as precise as firebase.database.ServerValue.TIMESTAMP
, but the difference is usually within milliseconds. The advantage is that it lets you create a negative timestamp on the client without having to update your Firebase node twice.
You grab the server time offset value when you need it from Firebase, generate the negative timestamp on the client, and then save your object in Firebase once.
See: https://groups.google.com/forum/#!topic/firebase-talk/EXMbZmyGWgE https://firebase.google.com/docs/database/ios/offline-capabilities#clock-skew (for iOS). https://firebase.google.com/docs/database/web/offline-capabilities#clock-skew (for web).
var offsetRef = firebase.database().ref(".info/serverTimeOffset");
offsetRef.on("value", function(snap) {
var offset = snap.val();
var negativeTimestamp = (new Date().getTime() + offset) * -1;
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With