delete a document in firebase when you know the field value - firebase

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. :)

Related

How can I check if a document contains a value inside a Firestore array?

I'm using Flutter and Firestore , where is this database I'm trying to be able to see if a value exists inside an array, but I only found solutions that didn't work for me, sometimes they were in another language, but I want to be able to see if a value exists inside an array in a document.
for example, I want to check if the user id userID1 is inside the array miembros marked in red in the following image
the idea is that I can do an if to add the value userID1 if it doesn't exist in the miembros array.
actually thank you very much for any help
If you just need to check if an array contains a specific value, then you can use arrayContains as shown below:
FirebaseFirestore.instance
.collection('grupos')
.where('miembros', arrayContains: 'ValueToCheck')
.get()
.then(...);
However, you can use arrayUnion() instead that will add the value if it's missing else it won't:
Firestore.instance
.collection('grupos')
.document('grupoId4')
.updateData({ 'array':FieldValue.arrayUnion('ValueToAddInArray') });
I found the solution, it turns out that the following can be done when one knows the document ID.
firestoreRef.where(FieldPath.documentId, isEqualTo: docID).snapshots();
by adding in where the FieldPath.documentId, isEqualTo: docID we can search based on the document id, after this we can do a forEach or whatever is estimated in the case.

How to make a query from a nested collection in firestore using flutter

I have a nested collection in firestore that I want to make a query from it.
As you can see the first collection called 'businessUsers' and the nested one called 'campaigns',
If I make a query for a field in the 'businessUsers' it's working OK:
return FirebaseFirestore.instance.collection("businessUsers").where('xxx',
isEqualTo:filterBusinessResult ).snapshots().map(_businessListFromSnapshot);
but how can I make a query to 'campaigns' collection field?
I tried
return FirebaseFirestore.instance.collection("businessUsers").doc().collection("campaigns").where('campaignCategory', isEqualTo:filterBusinessResult ).snapshots()
.map(_businessListFromSnapshot);
but it wont work.
Its important to note, that I need all the data with 'campaignCategory' == filterBusinessResult
any idea?
It depends on whether you want to query a specific user's campaigns, or the campaigns of all users together.
If you want to query the campaigns of a specific user, you need to query under their document:
FirebaseFirestore.instance
.collection("businessUsers").doc("your user ID").
.collection("campaigns")
.where('campaignCategory', isEqualTo:filterBusinessResult)
So you have to know the ID of the businessUsers document here.
If you want to query across all campaigns subcollections are once, that is known as a collection group query and would look like this:
FirebaseFirestore.instance
.collectionGroup("campaigns")
.where('campaignCategory', isEqualTo:filterBusinessResult)
The results are going to documents from the campaigns collection only, but you can look up the parent document reference for each DocumentSnapshot with docSnapshot.reference.parent.parent.
When querying something, .doc() requires the id of the document you're trying to get. So it's failing because it doesn't know which document in the businessUsers collection you're trying to fetch a subcollection on. You probably want to use a .collectionGroup() query here. They let you query all subcollections at once (see documentation here). With FlutterFire specifically, it's going to be something like:
var snapshots = FirebaseFirestore.instance.collectionGroup("campaigns")
.where("campaignCategory", isEqualTo: filterBusinessResult)
.snapshots();

seconds are lost when datetime transferred from flutter to firebase firestore

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.

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.

Flutter Firestore where clause using map

When a new activity is posted i add a new post document into the collection.
Inside this document i have a map where users add confirmation to the event marking it as true and adding his own id.
var snap = await Firestore.instance
.collection('user_posts')
.where("confirmations.${user.id}",isEqualTo: true)
.getDocuments();
With this snippet i'm able to get all the posts confirmed by the user. The issue here is to get this a index is required to perform this query. And this index can't be generic. I can't create a index for each user.
Some idea of how to get it?
Thanks!!
You'll want to turn the confirmations field into an array, and use the (relatively recent) array-contains and arrayUnion operations.
The equivalent query with an array like that would become:
var snap = await Firestore.instance
.collection('user_posts')
.where("confirmations", arrayContains: user.id)
.getDocuments();
And this way you only need an index on confirmations, which is added automatically.
For more on these see:
the blog post introducing these operations
the documentation on updating arrays
the documentation on array membership queries

Resources