I have an array of user emails that I want to then pull from firebase each of the corresponding user documents from a collection where one of the email matches. I don't want to pull the whole collection as it would be expensive. What is the easiest way to do this? I tried for looping over the array with individual gets to firebase but ran into promise issues as I want to do something in Javascript with them right after.
Thanks so much!
based on what i understood from your question i can only think of using await Promise.all() - you can look into this here.
as an example you could pass an array of promises to await Promise.all() so you could do
const res = await Promise.all(
array.map( x => db.collection('users')
.where('email' , '==', x.email).limit(1).get());
mind you that in this example you would still have to process the result as they will return a snapshot not a document ...
Update:
Hey there, i just noticed that you can use in operator in firebase query, which will return the values matching in a given array.
i'm not sure but maybe using it might be suitable in your use-case you can check the documentation here
Related
Talking about querying on Firestore, I found collection().where() function.
It would be a great help, if I could get some good information about the syntax of how does this .where() function works.
Found something like this in a tutorial.
const userExist = db.collection('data').where('users', 'array-contains', user.email);
How does the code above work?
Help would be appreciated.
The query in your question will return all documents that exist in the data collection, where the array property called users contains an email that is equal with what user.email returns.
I would like to update data in a document based on a query. Here is my code:
Firestore.instance
.collection("Categories")
.where("userEmail", isEqualTo: "${user?.email}")
.updateData({"category_budget_remaining": _remainingCategoryBudget2})
.then((value){});
I am getting the following error: The method 'updateData' isn't defined for the type 'Query'
after where() you need to get documents then do updating
where(...).getDocuments().then((val)=>
val.documents.forEach((doc)=> {
doc.reference.updateData({...})
});
});
this code selects and updates all documents that goes true for where condition. If you want do it just for 1 document then just add .limitTo(1) before getDocuments().
As you can see from the API documentation, where() returns a Query, and Query doesn't have a method called updateData(). So, what you're seeing here is no surprise.
Firestore doesn't offer a way to bulk update documents like a SQL "update where" command. What you will have to do is execute the query for the documents to change, iterate the documents in the result set, and update each one individually. Yes, it requires a document read for every document to change, and no, there are no alternatives for this.
For me worked by changing
.updateData
to just
.update
My answer is similar to #Habib Mahamadi but this is the correct and only way to acheive this functionality, my answer is little differente as firebase has changed names of functions.
Firestore.instance
.collection("Categories")
.where("userEmail", isEqualTo: "${user?.email}")
.then((value)=> value.docs.forEach((element){element.reference.update({"" : ""})});
I have been trying to get arrays working in Firebase, and I am aware that there are a lot of references and discussions about this online, and I have read through all of these and none of it works.
First off, the Firebase side. The structure containing the array and two example strings inside it:
Firebase Structure
collection -> document -> fields
userData profileImages URLs (array)
: https://firebasestorage.googleapis.com/v0/b/app-138804.appspot.com/o/jRwscYWLs1DySLMz7jn5Yo2%2Fprofile%2Fimage_picker4459623138678.jpg?alt=media&token=ec1043b-0120-be3c-8e142417
: https://firebasestorage.googleapis.com/v0/b/app-138804.appspot.com/o/jRwscYWLs3872yhdjn5Yo2%2Fprofile%2Fimage_picker445929873mfd38678.jpg?alt=media&token=ec3213b-0120-be9c-8e112632
The first issue I am facing is writing to this array in the database:
Firestore.instance.collection('userData').document('profileImages').updateData({
'URLs': _uploadedFileURL,
});
Whenever I add data to this array, it just overwrites the existing data. I need to be able to keep all the existing data intact and simply add the current new line to the array.
Once this is working, I then need to be able to return all of the strings in this array without needing to know how many of them there will be.
For this part, I basically have nothing at this point. I could show some of the things I have tried based on suggestions from other articles on this, but none of it is even close to working correctly.
im assuming that _uploadedFileURL is a String, and you are updating the property URLs, that's why your data gets overwritten, because you are changing the URLs value to a single string which is _uploadedFileURL. to solve this issue, simply get the current data inside profileImages before commiting the update. like so
final DocumentSnapshot currentData = await Firestore.instance.collection('userData').document('profileImages').get();
Firestore.instance.collection('userData').document('profileImages').updateData({
'URLs': [
...currentData.data['URLs'],
_uploadedFileURL
],
});
and for the second part of your question, all you need is to query for the profileImages
Future<List<String>> _getProfileImages() {
final document = Firestore.instance.collection('userData').document('profileImages').get();
return document.data['profileImages]
}
the result of the get method will be a DocumentSnapshot, and inside the data property will access the profileImages which is a List<String>.
Ok guys and girls I have worked this out. Part 1: appending data to an array in Firebase.
Firestore.instance.collection('userData').document('profileImages').updateDataupdateData({
'URLs':FieldValue.arrayUnion([_uploadedFileURL]),
});
Where _uploadedFileURL is basically a string, for these purposes. Now I have read that arrayUnion, which is super groovy, is only available in Cloud Firestore, and not the Realtime Database. I use Cloud Firestore so it works for me but if you are having issues this might be why.
Now what is extra groovy about Cloud Firestore is that you can similarly remove an element from the array using:
Firestore.instance.collection('userData').document('profileImages').updateDataupdateData({
'URLs':FieldValue.arrayRemove([_uploadedFileURL]),
});
So how to get this data back out again. A simple way I have found to get that data and chuck it into a local array is like so:
List imageURLlist = [];
DocumentReference document = Firestore.instance.collection('userData').document('profileImages');
DocumentSnapshot snapshot = await document.get();
setState(() {
imageURLlist = snapshot.data['URLs'];
});
From here at least you have the data, can add to it, can remove from it and this can be a platform for you to figure out what you want to do with it.
Will this work in Firebase Firestore?
var result = await firestoreInstance
.collection('messages')
.where('place', whereIn: ["value1","value2","value3","value4","value5","value6","value7","value8","value9"])
.orderBy('dateAdded')
.startAfterDocument(lastDocument)
.limit(documentLimit)
.getDocuments();
I mean, I want to filter data based on IN condition on one field ('place'), and then paginate it based on another field ('dateAdded').
Will it use a composite index on fields 'place' and 'dateAdded'?
I Firestore allows it, will it work in Flutter SDK?
Should work just fine - I already do similar actions in my code. One thing I found by trying - paging back with an "EndBeforeDocument" call seems to need to reverse the orderBy, so it will need to setup multiple compound indexes. A link to a page to create those indexes for you will be returned in the "err" from the .get() call (so set up your callbacks appropriately to catch this).
So Doug is generally right, btw, bad etiquette to ask questions without trying (and/or searching StackOverflow) - you just got lucky because I just wrote my own paging interface for a library for my application. While I intend to release the interface as an NPM package shortly, it probably won't help you - I'm using the Web API (javascript) under React.
I am a little confused about the difference between these two. My understanding is that getDocuments is a type of Future and seems to get the entire documents according to the query. while snapshots, on the other hand, is a type of Stream and, correct me if I'm wrong, I think it represents the results of the query? I need a more specific explanation of this issue. I will include some code snippets as an example for more clarification
getDocuments()
getUserById(String userId) async {
return await _firestore.collection("users").where("userId", isEqualTo: userId).getDocuments();
}
snapshots()
getUserById(String userId) async {
return await _firestore.collection("users").where("userId", isEqualTo: userId).snapshots();
}
So what's the difference?
When you call getDocuments(), the Firestore client gets the documents matching the query from the server once. Since this may take some time it returns a Future<QuerySnapshot>.
When you call snapshots() the Firestore client gets the documents, and then keeps watching the database on the server for changes that affect your query. So if document is written in the users collection that affects your query, your code gets called again. So this returns a stream of QuerySnapshot.
In both cases the results for the entire query are in the QuerySnapshot object.
I highly recommend reading the Firestore documentation on getting data once and on listening realtime updates. While they don't contain Flutter examples, the explanation in there applies equally to the Flutter libraries.
getDocuments():
It's used to provide data once. Cloud Firestore contains collections and inside these collections, you have documents that may contain subcollections or fields mapped to a value. To retrieve any of the doc fields to used it in widget this is used.
snapshots():
It will be called on every data change in your document query. For this StreamBuilder must be used to fetch fields as modified.
In short, it will do the job of setState() where it gives you the response for every modification so that UI can be updated.