seconds are lost when datetime transferred from flutter to firebase firestore - firebase

I am saving documents in firestore using datetime as their id but if I saved more than one in the same minute it deletes the old one and replace it with newest one "in the same minute"
I check the date time in flutter it has seconds and milliseconds
but in firestore it's only minutes and seconds and milliseconds are set to 00:000
meaning 2020-12-04 13:51:03.836035 in flutter turns to 2020-12-04 13:51:00.000 in firestore
how can I solve this?
I use
users
.doc(auth.currentUser.uid)
.collection('documents')
.doc(dateTime.toString())
.set({
'day': DateTime.parse(dateTime.toString().substring(0, 10)),
'document': {
dateTime.toString(): {'documentContent': content.text, 'documentDateTime': dateTime}
}
}, SetOptions(merge: true))
.then((value) => print("Document Added"))
.catchError((error) => print("Failed to add Document: $error"));
dateTime is a DateTime object btw
I am talking about this part 'documentDateTime': dateTime or dateTime.toString()

I have used the code you shared to create a document and then I have downloaded the documents back to Flutter app and printed it's contents and here's what I get:
// Add code right below your snippet
users
.doc(auth.currentUser.uid)
.collection('documents')
.doc(dateTime.toString())
.get()
.then((doc) => print(doc.data()));
// Output:
{document:
{2020-12-18 13:49:58.496955:
{documentContent: xx,
documentDateTime: Timestamp(seconds=1608299398, nanoseconds=496000000)}},
day: Timestamp(seconds=1608249600, nanoseconds=0)}
Indeed the field documentDateTime has the milliseconds data. What happens is that the Firestore Console UI doesn't show milliseconds data even though the data is there.

I strongly recommend not using date strings as document IDs. This is causing you trouble today, and will continue to cause you trouble in the future.
Instead, store the time as a field in the document (in whatever format you find most convenient), and use that field to query and order the documents. When creating the document, you can take the random document ID provided by add().
If you need to update something in that document, you can use the fields of the document to locate it with a query, then update the document after you find it. It is up to you to figure out how best store the time so that you can locate the document again. This is something you will need to think through carefully.

Related

Firebase snapshot listener filter

I have a Firestore DB. Is it possible to filter snapshots coming from it based on some field if add add a listener? What I need is: “send me an updated document only if this field equals this value”
What I surely can do is just check manually each new snapshot and return/propagate document if it passes the filter but I was thinking about sparing some transferred data and hit less limits
You can make a query by filtering something then adding a listener for this like the below code:
// get all document in collection "cities" that has attribute "state" equal to "CA"
db.collection("cities").whereField("state", isEqualTo: "CA")
.addSnapshotListener { querySnapshot, error in
guard let documents = querySnapshot?.documents else {
print("Error fetching documents: \(error!)")
return
}
let cities = documents.map { $0["name"]! }
print("Current cities in CA: \(cities)")
}
Ref: https://firebase.google.com/docs/firestore/query-data/listen#listen_to_multiple_documents_in_a_collection
Cloud Firestore listeners fire on the document level. So if you have multiple fields in a document and the value of the fields in the document changes, your listener will fire. So you'll have to pay a read operation, each time something in the document changes.
It's true that you can attach a listener and get only the documents that have set a field to a particular value, but that doesn't mean you can restrict the SDK to read the value only when that field is changed to a value of your choice.
There is no way you can read a document, only when a field gets a particular value. You're always charged with a read operation, each time a value changes, no matter what the value is. So if the new value is the value that passes your filters, then you can go ahead with your logic.
I was thinking about sparing some transferred data and hitting less limits.
Everything in Firestore it's about the number of reads, writes, and deletes you perform. And the amount of bandwidth you are using. But unfortunately, you cannot reduce the costs that way.

increment document id by timestamp in firestore

My cloud firestore database has an "orders" collection and in HTML I have a 'save' button to add document(s) into that "orders" collection upon clicking. Now, using add will assign auto-generated ID for each document.
What if I want to customise such ID by timestamp? So that the document created yesterday will be assigned an index as '1', and the following document created will be '2', etc...
What you're trying to do is not compatible with the way Cloud Firestore was designed. Firestore will not assign monotonically increasing numbers for document IDs. This just doesn't scale massively as required by Firestore and would introduce performance bottlenecks.
If you want to be able to sort documents by timestamp, the best strategy is to add a timestamp field to each document, then use that field in an ordered query.
Note that you could try to write a lot of code to get this done the way you want, but you are MUCH better off accepting the random IDs and using fields to filter and order data.
in some case, when you need to save several docs in different collection due to an event occurs, it's better to same all docs with same id in different collections with single firestore server's timestamp. you get the timestamp like below:
const admin = require('firebase-admin')
const ts = admin.firestore.Timestamp.now().toMillis().toString()
by doing this, when you need to read all those docs, you only need to query once to get timestamp, then read all other doc by timestamp directly.
it should be faster than query the timestamp inside document fields for each collections

Flutter Firebase documents are randomly ordered

I made a simple chat app using Flutter. My app is functioning perfectly fine (getting and dumping data into firebase) but once my messages get into my database, they are randomly ordered resulting in my msgs getting displayed in a random order.
I have tried reversing the SnapshotQueue in my Flutter code but that did not help...
You will need to attach document names to your documents before uploading them.
I think you are experiencing this issue because your documents are being given Auto Ids.
Try using the current timestamp as the document name. this will help arrange documents in order according to time uploaded.
Firestore.instance.collection(CollectionName).document(Timestamp.now()).setData(messageMap);
i hope this is what you need. if not. Please share your code that uploads the message to database.
Add a field like datePublished = DateTime.now() to each message document as
it gets created to
store the timestamp of when the message was created
Then you can use datePublished field to order your documents of your QuerySnapshot like this:
QuerySnapshot snapshot = await collection.orderBy('datePublished', descending: true).get();
now your messages are arranged in chronological order from the latest
to earliest.

delete a document in firebase when you know the field value

Context: In the frontend the user can enter of delete dates for availability. This is how I added a date:
Firestore.instance.collection('availableDates').add({
'availableDates':date});
But I also need to delete a document from a collection in Firestore. I don't know the document id but I know the the field value which is unique. How would I go about deleting the document if I know the field value within the document. Here is a screen shot of firestore:
You can fetch the document first and then delete the document. For example:
var collection = FirebaseFirestore.instance.collection('countries');
var snapshot = await collection.where('city', isEqualTo: 'CA').get();
await snapshot.docs.first.reference.delete();
If anyone is confused after the update of why this code is not working please refer to this one. Update of March 21st, 2021.
refUser.where("city", isEqualTo: "CA").get().then((snapshot){
snapshot.docs.first.reference.delete();
});
I took a bit of time myself to get around this but if it helps even a single person stuck like me then it's all worth it. :)

How to update avatar/photoUrl on multiple locations in the Firestore?

In Firestore I am trying to update avatar (photoUrl) on multiple locations when the user changes the avatar.
Data structure: https://i.imgur.com/yOAgXwV.png
Cloud function:
exports.updateAvatars = functions.firestore.document('users/{userID}').onUpdate((change, context) => {
const userID = context.params.userID;
const imageURL = change.after.data().avatar;
console.log(userID);
console.log(imageURL);
});
With this cloud function, I am watching on user update changes. When the user changes avatar I got userID and a photo URL. Now I want to update all "todos" where participant UID is equal to userID.
You could use the array_contains operator for your query. This allows you to search for array values inside your documents.
https://firebase.google.com/docs/firestore/query-data/queries#array_membership
If you found your documents you have to update the URL on all documents and write the updated documents back to the database.
But this causes a lot of unnecessary writes especially if your todos collection gets bigger and you want to archive the todos data.
Simpler solution:
I suspect a to do list does not have more then 10 users if so this is a lot of trouble to save some document reads.
I would recommend you to just load all user documents you need to show the avatar on the to do list.

Resources