firebase timestamps not serverside created - javascript

I have a chat app in react native using firebase and it is crucial to me that the timestamps are all synchronised and created serversided, not from the client. Clients can have different times depending on the settings on the mobile phone.
I tried out following function to prove my point:
const comparetimes = async () => {
const timezone1 = firebase.firestore.Timestamp.now();
const timezone2 = (firebase.firestore.Timestamp.now()).toMillis();
const timezone3 = Date.now();
console.log(timezone1);
console.log(timezone2);
console.log(timezone3)
}
What shocked me is the result of this function:
{"nanoseconds": 79000000, "seconds": 1641054839}
1641054839080
1641054839080
Apperently the firebase timestamp is the exact same as Date.now() which is a direct timestamp taken from the mobile phone, and therefore unaccurate.
What can I do to have timestamps not created by the client but by the server, in this example firebase? Do I need to checkout some APIs or is there something I miss here?

When you call Timestamp.now(), it really is just taking the timestamp on the client device. That's expected.
Read the documentation on how to use server timestamps. You must use the token value returned by firestore.FieldValue.serverTimestamp() in order to tell Firestore to use the current moment in time as the request reaches the server.
When storing timestamps, it is recommended you use the serverTimestamp
static method on the FieldValue class. When written to the database,
the Firebase servers will write a new timestamp based on their time,
rather than the clients. This helps resolve any data consistency
issues with different client timezones:
firestore().doc('users/ABC').update({
createdAt: firestore.FieldValue.serverTimestamp(),
});
Also read:
https://medium.com/firebase-developers/the-secrets-of-firestore-fieldvalue-servertimestamp-revealed-29dd7a38a82b

Related

matrix-js-sdk setup and configuration

I am having some issues trying to connect to a matrix server using the matrix-js-sdk in a react app.
I have provided a simple code example below, and made sure that credentials are valid (login works) and that the environment variable containing the URL for the matrix client is set. I have signed into element in a browser and created two rooms for testing purposes, and was expecting these two rooms would be returned from matrixClient.getRooms(). However, this simply returns an empty array. With some further testing it seems like the asynchronous functions provided for fetching room, member and group ID's only, works as expected.
According to https://matrix.org/docs/guides/usage-of-the-matrix-js-sd these should be valid steps for setting up the matrix-js-sdk, however the sync is never executed either.
const matrixClient = sdk.createClient(
process.env.REACT_APP_MATRIX_CLIENT_URL!
);
await matrixClient.long("m.login.password", credentials);
matrixClient.once('sync', () => {
debugger; // Never hit
}
for (const room of matrixClient.getRooms()) {
debugger; // Never hit
}
I did manage to use the roomId's returned from await matrixClient.roomInitialSync(roomId, limit, callback), however this lead me to another issue where I can't figure out how to decrypt messages, as the events containing the messages sent in the room seems to be of type 'm.room.encrypted' instead of 'm.room.message'.
Does anyone have any good examples of working implementations for the matrix-js-sdk, or any other good resources for properly understanding how to put this all together? I need to be able to load rooms, persons, messages etc. and display these respectively in a ReactJS application.
It turns out I simply forgot to run startClient on the matrix client, resulting in it not fetching any data.

How to get current timestamp with Firebase react native?

Alright I've followed this question verbatim Firebase TIMESTAMP to date and Time and am posting to my Firebase database like this:
function storeUserInfo(username, industry, role, color) {
if (username != null && industry != null && role != null && color != null) { //use for errors later
let timestamp = firebase.firestore.FieldValue.serverTimestamp();
let push = firebase.database().ref('users').push();
push.set({
name: username,
industry: industry,
role: role,
color: color,
date: new Date(timestamp.toDate()).toUTCString()
});
}
}
This gives me the error: timestamp.toDate() is not a function
Ive tried several other methods like Firebase.ServerValue.TIMESTAMP but need to get the current formatted date for Firebase database. How can I do this?
You have a couple of things going wrong here. Firstly, you're trying to write to Realtime Database (via firebase.database()), but you're trying to use Firestore's timetamp with it. Firestore and Realtime Database are different databases with different APIs. A Firestore timestamp would not be helpful to you here.
If you want to get a date as reckoned by the client machine's clock, simply call new Date() with no arguments.
push.set({
name: username,
industry: industry,
role: role,
color: color,
date: new Date().toUTCString()
});
I suggest actually just storing an integer instead of a formatted string - it will probably be easier for you in the long term.
If you want to write an integer value based on the database server's sense of time, you would do this instead, using ServerValue.TIMESTAMP, which gets an actual integer value as soon as the write hits the server:
date: firebase.database.ServerValue.TIMESTAMP
If you were actually just hoping to get a server timestamp from Firestore's Timestamp API, that's not possible, because the server timestamp can only be calculated on the server. The error is telling you that there is no toDate() method available on the FieldValue type object returned by FieldValue.serverTimestamp(). It doesn't return a Timestamp. It returns a token that you can provide to Firestore that interprets the timestamp on the server and not in the client app. You should provide this token directly to Firestore if you want the server's timestamp in that field:

Firestore slow performance issue on getting data

I'm having slow performance issues with Firestore while retrieving basic data stored in a document compared to the realtime database with 1/10 ratio.
Using Firestore, it takes an average of 3000 ms on the first call
this.db.collection(‘testCol’)
.doc(‘testDoc’)
.valueChanges().forEach((data) => {
console.log(data);//3000 ms later
});
Using the realtime database, it takes an average of 300 ms on the first call
this.db.database.ref(‘/test’).once(‘value’).then(data => {
console.log(data); //300ms later
});
This is a screenshot of the network console :
I'm running the Javascript SDK v4.50 with AngularFire2 v5.0 rc.2.
Did anyone experience this issue ?
UPDATE: 12th Feb 2018 - iOS Firestore SDK v0.10.0
Similar to some other commenters, I've also noticed a slower response on the first get request (with subsequent requests taking ~100ms). For me it's not as bad as 30s, but maybe around 2-3s when I have good connectivity, which is enough to provide a bad user experience when my app starts up.
Firebase have advised that they're aware of this "cold start" issue and they're working on a long term fix for it - no ETA unfortunately. I think it's a separate issue that when I have poor connectivity, it can take ages (over 30s) before get requests decide to read from cache.
Whilst Firebase fix all these issues, I've started using the new disableNetwork() and enableNetwork() methods (available in Firestore v0.10.0) to manually control the online/offline state of Firebase. Though I've had to be very careful where I use it in my code, as there's a Firestore bug that can cause a crash under certain scenarios.
UPDATE: 15th Nov 2017 - iOS Firestore SDK v0.9.2
It seems the slow performance issue has now been fixed. I've re-run the tests described below and the time it takes for Firestore to return the 100 documents now seems to be consistently around 100ms.
Not sure if this was a fix in the latest SDK v0.9.2 or if it was a backend fix (or both), but I suggest everyone updates their Firebase pods. My app is noticeably more responsive - similar to the way it was on the Realtime DB.
I've also discovered Firestore to be much slower than Realtime DB, especially when reading from lots of documents.
Updated tests (with latest iOS Firestore SDK v0.9.0):
I set up a test project in iOS Swift using both RTDB and Firestore and ran 100 sequential read operations on each. For the RTDB, I tested the observeSingleEvent and observe methods on each of the 100 top level nodes. For Firestore, I used the getDocument and addSnapshotListener methods at each of the 100 documents in the TestCol collection. I ran the tests with disk persistence on and off. Please refer to the attached image, which shows the data structure for each database.
I ran the test 10 times for each database on the same device and a stable wifi network. Existing observers and listeners were destroyed before each new run.
Realtime DB observeSingleEvent method:
func rtdbObserveSingle() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from RTDB at: \(start)")
for i in 1...100 {
Database.database().reference().child(String(i)).observeSingleEvent(of: .value) { snapshot in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
let data = snapshot.value as? [String: String] ?? [:]
print("Data: \(data). Returned at: \(time)")
}
}
}
Realtime DB observe method:
func rtdbObserve() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from RTDB at: \(start)")
for i in 1...100 {
Database.database().reference().child(String(i)).observe(.value) { snapshot in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
let data = snapshot.value as? [String: String] ?? [:]
print("Data: \(data). Returned at: \(time)")
}
}
}
Firestore getDocument method:
func fsGetDocument() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from FS at: \(start)")
for i in 1...100 {
Firestore.firestore().collection("TestCol").document(String(i)).getDocument() { document, error in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
guard let document = document, document.exists && error == nil else {
print("Error: \(error?.localizedDescription ?? "nil"). Returned at: \(time)")
return
}
let data = document.data() as? [String: String] ?? [:]
print("Data: \(data). Returned at: \(time)")
}
}
}
Firestore addSnapshotListener method:
func fsAddSnapshotListener() {
let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
print("Started reading from FS at: \(start)")
for i in 1...100 {
Firestore.firestore().collection("TestCol").document(String(i)).addSnapshotListener() { document, error in
let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
guard let document = document, document.exists && error == nil else {
print("Error: \(error?.localizedDescription ?? "nil"). Returned at: \(time)")
return
}
let data = document.data() as? [String: String] ?? [:]
print("Data: \(data). Returned at: \(time)")
}
}
}
Each method essentially prints the unix timestamp in milliseconds when the method starts executing and then prints another unix timestamp when each read operation returns. I took the difference between the initial timestamp and the last timestamp to return.
RESULTS - Disk persistence disabled:
RESULTS - Disk persistence enabled:
Data Structure:
When the Firestore getDocument / addSnapshotListener methods get stuck, it seems to get stuck for durations that are roughly multiples of 30 seconds. Perhaps this could help the Firebase team isolate where in the SDK it's getting stuck?
Update Date March 02, 2018
It looks like this is a known issue and the engineers at Firestore are working on a fix. After a few email exchanges and code sharing with a Firestore engineer on this issue, this was his response as of today.
"You are actually correct. Upon further checking, this slowness on getDocuments() API is a known behavior in Cloud Firestore beta. Our engineers are aware of this performance issue tagged as "cold starts", but don't worry as we are doing our best to improve Firestore query performance.
We are already working on a long-term fix but I can't share any timelines or specifics at the moment. While Firestore is still on beta, expect that there will be more improvements to come."
So hopefully this will get knocked out soon.
Using Swift / iOS
After dealing with this for about 3 days it seems the issue is definitely the get() ie .getDocuments and .getDocument. Things I thought were causing the extreme yet intermittent delays but don't appear to be the case:
Not so great network connectivity
Repeated calls via looping over .getDocument()
Chaining get() calls
Firestore Cold starting
Fetching multiple documents (Fetching 1 small doc caused 20sec delays)
Caching (I disabled offline persistence but this did nothing.)
I was able to rule all of these out as I noticed this issue didn't happen with every Firestore database call I was making. Only retrievals using get(). For kicks I replaced .getDocument with .addSnapshotListener to retrieve my data and voila. Instant retrieval each time including the first call. No cold starts. So far no issues with the .addSnapshotListener, only getDocument(s).
For now, I'm simply dropping the .getDocument() where time is of the essence and replacing it with .addSnapshotListener then using
for document in querySnapshot!.documents{
// do some magical unicorn stuff here with my document.data()
}
... in order to keep moving until this gets worked out by Firestore.
Almost 3 years later, firestore being well out of beta and I can confirm that this horrible problem still persists ;-(
On our mobile app we use the javascript / node.js firebase client. After a lot of testing to find out why our app's startup time is around 10sec we identified what to attribute 70% of that time to... Well, to firebase's and firestore's performance and cold start issues:
firebase.auth().onAuthStateChanged() fires approx. after 1.5 - 2sec, already quite bad.
If it returns a user, we use its ID to get the user document from firestore. This is the first call to firestore and the corresponding get() takes 4 - 5sec. Subsequent get() of the same or other documents take approx. 500ms.
So in total the user initialization takes 6 - 7 sec, completely unacceptable. And we can't do anything about it. We can't test disabling persistence, since in the javascript client there's no such option, persistence is always enabled by default, so not calling enablePersistence() won't change anything.
I had this issue until this morning. My Firestore query via iOS/Swift would take around 20 seconds to complete a simple, fully indexed query - with non-proportional query times for 1 item returned - all the way up to 3,000.
My solution was to disable offline data persistence. In my case, it didn't suit the needs of our Firestore database - which has large portions of its data updated every day.
iOS & Android users have this option enabled by default, whilst web users have it disabled by default. It makes Firestore seem insanely slow if you're querying a huge collection of documents. Basically it caches a copy of whichever data you're querying (and whichever collection you're querying - I believe it caches all documents within) which can lead to high Memory usage.
In my case, it caused a huge wait for every query until the device had cached the data required - hence the non-proportional query times for the increasing numbers of items to return from the exact same collection. This is because it took the same amount of time to cache the collection in each query.
Offline Data - from the Cloud Firestore Docs
I performed some benchmarking to display this effect (with offline persistence enabled) from the same queried collection, but with different amounts of items returned using the .limit parameter:
Now at 100 items returned (with offline persistence disabled), my query takes less than 1 second to complete.
My Firestore query code is below:
let db = Firestore.firestore()
self.date = Date()
let ref = db.collection("collection").whereField("Int", isEqualTo: SomeInt).order(by: "AnotherInt", descending: true).limit(to: 100)
ref.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
let data = document.data()
//Do things
}
print("QUERY DONE")
let currentTime = Date()
let components = Calendar.current.dateComponents([.second], from: self.date, to: currentTime)
let seconds = components.second!
print("Elapsed time for Firestore query -> \(seconds)s")
// Benchmark result
}
}
well, from what I'm currently doing and research by using nexus 5X in emulator and real android phone Huawei P8,
Firestore and Cloud Storage are both give me a headache of slow response
when I do first document.get() and first storage.getDownloadUrl()
It give me more than 60 seconds response on each request. The slow response only happen in real android phone. Not in emulator. Another strange thing.
After the first encounter, the rest request is smooth.
Here is the simple code where I meet the slow response.
var dbuserref = dbFireStore.collection('user').where('email','==',email);
const querySnapshot = await dbuserref.get();
var url = await defaultStorage.ref(document.data().image_path).getDownloadURL();
I also found link that is researching the same.
https://reformatcode.com/code/android/firestore-document-get-performance

Timestamps for messages

I'm using firebase's database to host a real time messaging web app. I've finished the basic implementation but now want to add timestamps for users to see when messages were sent.
To add a message to a chatroom I use firebase.push() with the value as the sent message. I guess I'll have to switch this to .update() with the value as an object with the fields message and time sent.
I'm trying to figure out how to populate this time sent. I've heard of firebase.database.ServerValue.TIMESTAMP but from what I can tell it's hard to change that into a date and time. I'm heavily considering a unix timestamp like this var unix = Math.round(+new Date()/1000); since this is easy to convert.
Does anybody with any experience have any tips for which direction I should take? I don't need the timestamp to be super precise, just the date, hour, and minute.
When you write firebase.database.ServerValue.TIMESTAMP to a node, the value becomes a UNIX timestamp. See the Firebase reference documentation for an example how to write this:
var sessionsRef = firebase.database().ref('sessions');
var mySessionRef = sessionsRef.push();
mySessionRef.update({ startedAt: firebase.database.ServerValue.TIMESTAMP });
When you read this value, you can convert it back into a Date object with:
sessionsRef.on('child_added', function(snapshot) {
var startedAt = new Date(snapshot.val().startedAt);
});

Are Javascript date/time functions dependent on the client machine?

I was wondering if Javascript date/time functions will always return correct, universal dates/times
or whether, Javascript being a client-side language, they are dependent on what the client machine has its date set to.
If it is dependent on the client machine, what is the best way to get the correct universal time?
Javascript only knows as much about the correct time as the environment it is currently running within, and Javascript is client-side.
So, Javascript is at the mercy of the user having the correct time, AND timezone, settings on the PC on which they are browsing.
If the user has the incorrect time zone, but correct time, then functions depending on time zones like getUTCDate() will be incorrect.
If the user has the incorrect time, then all time-related functions in Javascript will be incorrect.
One could make the argument, however, that if the user wanted correct times on their PC they would have set the correct time. The counter to that is that the user may not know how to do that.
Edit Jun 2020: It is common now for operating systems to update the computer's system time automatically from a time server, significantly reducing the chances of incorrect time on the client. There is still a possibility of an incorrect time zone, but this too is often geo-detected somehow by systems during installation and/or is tied to the user's supplied country of residence in their relevant online account.
As thomasrutter has said javascript date functions are reliant on the client's machine. However if you want to get an authoritative date you could make and ajax request to your server that just returns the date string. You can then convert the date string into a date object with the following
var ds = ... // Some ajax call
var d = new Date(ds);
or whether, Javascript being a client-side language, they are dependent on what the client machine has its date set to.
Yes, this is correct.
If it is dependent on the client machine, what is the best way to get the correct universal time?
To get the time/date from an authoritative source, not from a client machine.
The methods do what they're documented to do. The best way to get UTC info is obviously to use the UTC methods:
getUTCFullYear(), getUTCMonth(), getUTCDate(), etc.
Javascript's date() constructor will always get the time of local machine.
The best way to get the universal time are
1) get the time from your server by an ajax call. This method will always show your server time no matter where your user is.
2) Get the time from an third party server. Use a third party server to get time from any time zone / country of the world. Here I'm explaining this method by using plain javascript and axios. The service I'm using is worldtimeapi.org/
VANILLA JS
function getTime(url) {
return new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
req.open("GET", url);
req.onload = () =>
req.status === 200
? resolve(req.response)
: reject(Error(req.statusText));
req.onerror = (e) => reject(Error(`Network Error: ${e}`));
req.send();
});
}
Now Use this function to make the ajax call
let url = "http://worldtimeapi.org/api/timezone/Etc/GMT";
getTime(url)
.then((response) => {
let dateObj = JSON.parse(response);
let dateTime = dateObj.datetime;
console.log(dateObj);
console.log(dateTime);
})
.catch((err) => {
console.log(err);
});
AXIOS
axios({
url:"http://worldtimeapi.org/api/timezone/Etc/GMT",
method: "get",
})
.then((response) => {
let dateObj = response.data;
let dateTime = dateObj.datetime;
console.log(dateObj);
console.log(dateTime);
})
.catch((err) => {
console.log(err);
});
Hope that helps. Bear one thing in mind though, worldtimeapi.org/ is a third party service. If they choose to terminate their service, your code will break. Happy coding.

Categories

Resources