Update document value in Firestore Cloud with Flutter, having only a unique key value of such document - firebase

I'm new to Cloud Firestore but already made some CRUD operations but now I'm really stuck with this thing.
Each document inside the 'tiposFrota' collection has a key 'nome:' with a unique value, no document will have the same value for the 'nome:' key.
The problem is, whenever the user adds another 'Truck' to some other collections I need to increment the value of 'qtde:' by one, and when they remove 'Truck' the program will increment the number by -1, working as a counter.
I managed to create an operation to update a key value, but only when you have the document id, but in this case the id is autogenerated because they may add or remove standard values from the 'tiposFrota' collection.
FirebaseFirestore.instance
.collection('controladores')
.doc('contadores')
.update({'numFrota': FieldValue.increment(1)}),
I'm really stuck with this, if anyone could please help.
Thanks!

Woah, managed to find a solution by myself, this post Get firestore collections based on values in array list in flutter.
Since the 'nome:' value is unique for each document inside the 'tiposFrota' collection I can use the .where statement as a filter for said document, get the snapshot with all the documents (but only getting one, obviously) and use the 'forEach' method to create a function using the '.id' parameter when calling the document.
FirebaseFirestore.instance
.collection('tiposFrota')
.where('nome', isEqualTo: carMake)
.get()
.then((querySnapshot) {
querySnapshot.docs.forEach((element) {
FirebaseFirestore.instance
.collection('tiposFrota')
.doc(element.id)
.update({
'qtde': FieldValue.increment(1)});
});
}),

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 get a specific document from QuerySnapshot in Flutter Firestore?

Guys how can i retrieve a specific document from QuerySnapshot.docs?
I once get all documents of a collection.
And after some code, i want to get a document by its ID from that collection.
I want to get that document specifically from this QuerySnapshot since i don't want to be messed with await later in my code.
So if i can get all documents all at once, why would i get every document one by one later with async call which would waste my time?
The thing would look like this:
QuerySnapshot usersSnapshot = await FirebaseFirestore.instance.collection("users").get();
//
//some code
//
DocumentSnapshot userDoc = usersSnapshot.docs.doc("user12345");
I want to get document with id user12345.
Is there any function like this .doc(ID) that i can apply on QuerySnapshot??
No, there is no such method on QuerySnapshot. You have to locate the document you want by iterating the results of the query in the docs property, and check each DocumentSnapshot for the ID you're looking for.
If you want to make that easier for yourself for repeated lookups, you can iterate the docs list, and build a Map of document snapshots keyed by the ID. Query the Map for each document you want.

Flutter Firebase: Retrieve a list of documents, limited to IDs in an array?

I'm working on a Flutter app where each user can create projects, and share projects with other users. I've created a 'shares' collection, where each user's ID is a document, and within that document, all project IDs that have been shared with that user are collected like so, with a boolean that represents whether or not the share has been accepted yet:
Next, I created a collection of the projects themselves, like so:
Now, I'd like to query the 'projects' collection and return only the projects that are in a given user's 'shares' list. First off, how can I get each document in the share list's ID? And secondly, is it possible to compare that ID to the contents of a List using a .where() clause?
I've been trying something like this, but to no avail:
Stream<List<Map<String, dynamic>>> getListOfProjectsForUser({#required List<String> shares}) {
var ref = _firestore.collection('projects');
return ref
.where(shares, arrayContains: ref.id)
.snapshots()
.map((QuerySnapshot snapshot) => snapshot.docs.map((DocumentSnapshot doc) => doc.data()).toList());
}
I also tried this:
Stream<List<Map<String, dynamic>>> getListOfProjectsForUser({#required List<String> shares}) {
var ref = _firestore.collection('projects');
return ref
.where(shares, arrayContains: FieldPath.documentId)
.snapshots()
.map((QuerySnapshot snapshot) => snapshot.docs.map((DocumentSnapshot doc) => doc.data()).toList());
}
Is what I'm trying to do even possible? I've been messing with this for two days and my head's exploding. Any help would be greatly appreciated. Thanks in advance.
You'll need two operations.
Read the document for the user, to determine the list of project IDs.
Perform a in query for the project documents matching those IDs. The in operator accepts up to 10 IDs, so if you have more than 10 projects you'll need multiple queries and merge the results in your application code.
var citiesRef = db.collection("projects");
citiesRef.where(FieldPath.documentId, arrayContains: ['project1id', 'project2id']);
Also see:
The FlutterFire documentation for the where(field, whereIn:) operation
The FlutterFire documentation for the FieldPath.documentId field
First off, how can I get each document in the share list's ID?
For this, you're required to actually query the entire collection. You can iterate the results to collect the IDs of each document. There is no easy way to just get a list of IDs directly from web and mobile client code. See: How to get a list of document IDs in a collection Cloud Firestore?
And secondly, is it possible to compare that ID to the contents of a List using a .where() clause?
If you have a list of document ID strings in memory that could be any length, you will need to perform a query filtering projects for "projOwner" for each individual ID. There are no SQL-like joins in Firestore, so you can't simply join the two collections together with a single query.
Here's how you do a single one - you have to call out the name of the field to filter on:
firestore
.collection("projects")
.where("projOwner", isEqualTo: id)
If you have 10 or less share IDs in the list, you can use an "in" query to find matches from projects, and it will not work with any more.
firestore
.collection("projects")
.where("projOwner", whereIn: listOfIds)
So, if you think the list could ever be larger than 10, you should just start by performing individual queries for each share ID.
if 'arrayContains' is not working try 'whereIn'.
var citiesRef = db.collection("projects");
citiesRef.where(FieldPath.documentId, whereIn: ['project1id',
'project2id']);

How to read a firestore value in a map?

I'm trying to read the value for exp_date in my flutter app as seen in this picture:
The field/value pair is in a map called Card which is in a sub collection called sources . I can read the value by putting in the DocId for the sources collection(the other docId is the firebase user uid) with the following:
StreamBuilder(stream: Firestore.instance.collection('stripe_customers').document(userId).collection('sources').document('qRvDob75kTzhT3').snapshots(),builder: (context,snapshot){
if(!snapshot.hasData){
return new Text("Loading");
}
var userDocument = snapshot.data;
return new Text(userDocument["card"]['exp_year'].toString());
},),
But obviously this isn't very practical. How do I access the Card map value without knowing the document id?
There are two ways to get the contents of a document:
Know its entire, unique path.
Make query against a known collection to get matching documents.
If you don't know the id required by #1, you will have to try #2. But since you don't seem to have have a way to filter the documents in that collection, you will have to fetch ALL of the documents. This is probably not what you want to do for scalability purposes.
Give some consideration about how you want to find the data in Firestore before you write the documents.

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