flutter firebase querysnapshot: case insensitive method in dart code - firebase

I'm flutter user with firebase connected.
I'm trying to call list of users from cloud firestore with querysnapshot when users call search feature and then string submitted. What I've tried is snippet below:
Future<QuerySnapshot> allUsers = usersReference
.where("profileName",
isGreaterThanOrEqualTo: str)
.getDocuments();
setState(() {
futureSearchResults = allUsers;
});}
The problem is I have to make 'profileName' called by querysnapshot 'case insensitive'. For example, profileName 'HELLO WORLD' in cloud firestore must be printed as 'hello world' in my android studio flutter console. So i need a flutterFire method to convert all uppercase characters from cloud firestore to lowercase characters. Unfortunately, i couldn't find simple property to set case-insensitive from flutterFire plugIn.. ]:
Furthermore, what i'm trying to call from firestore is not a bunch of strings but certain form of document which is going to be converted to certain custom class written in dart. It made me unavailable with neat dart methods like toLowerCase().
If anyone know method in dart code to change uppercase characters from cloud firestore to lowercase, please share your knowledge.
Clear answers so appreciated!! Thank you in advance [:

Firestore does not offer case-insensitive queries. If you need to query for strings using any case, you should store a "canonical" version of the string in Firestore, the make the client code use that for all queries. So, for example, you could store all strings as lowercase in the database, then require your client code to convert all strings to lowercase before querying.

Related

Firebase Firestore - Best way to call a bunch of where gets?

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

How to avoid double Cloud Firestore write when uploading Storage file using the document ID and passing the DownloadURL

I am working on a Flutter app connected to Firebase Cloud Firestore and Storage, and I want to create documents in Cloud Firestore that contain the downloadURL of files in Storage. However, I also need the filename to be the unique ID of the same Firestore document. Right now I upload the file after I create the document, but it would cost me an extra write to update the Firestore document afterwards.
I want to prevent this. It might work if I could access the id of the newly created document within the add() function, so that I can pass it to the storageTask, which would return the downloadURL directly inside the add() function. Another option would be if I could create a document, get its ID, then do the upload task, and write all the data afterwards, but I''m not sure if this would count as one write or two, nor do I know how to create a document without setting any data.
What I have now is roughly like this:
CollectionReference activities = FirebaseFirestore.instance.collection('activities');
activities.add({
'postDate': DateTime.now(),
}).then((value) => _startUpload(id: value.id));
Where _startUpload is a function that uploads a file to Storage, and could potentially return a downloadURL. I want to be able to access that URL in the add function like this:
CollectionReference activities = FirebaseFirestore.instance.collection('activities');
activities.add({
'postDate': DateTime.now(),
'downloadURL': _startUpload(id: SomehowGetThisDocuments.id)
});
You can do something like described in the last paragraph of this section in the documentation:
newActivityRef = activities.document();
newActivityRef.set({
'postDate': DateTime.now(),
'downloadURL': _startUpload(id: newActivityRef.documentID)
});
This should count as one write as .document().set() is equivalent to .add() according to the documentation.

Compound queries in Firestore - different fields in "order by" and "where"

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.

What is the difference between getDocuments() and snapshots() in Firestore?

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.

Uploading Set<String> gives error in flutter

Okay, so I'm creating chips tiles that are stored in a Set, but when I try to upload it to firebase I get this error "Unhandled Exception: Invalid argument: Instance of '_CompactLinkedHashSet'"
I isolated the code and simplified it so it looks like this:
...
Set<String> _tags = <String>{};
_tags.add('Test1');
Firestore.instance
.collection('tags')
.document(tagsID)
.setData({
'tags': _tags,
});
...
I've tried debugging it, and I can't get it to upload so is there any other kind of way I can get the data from the set and upload it to Firebase? Another data type I can use that Firebase will accept?
Take a look at the data types that Firestore supports. Sets are not supported. You could convert your set to a JSON string, or to a list:
List<String> tagsList = List<String>.from(_tags);
Adding on to Bryson Thill's answer, if you need to use Sets in your code, I'd recommend you use the toList() method before uploading to Firestore.
I would suggest you following the answer from this question:
Adding an Object to Cloud Firestore using Flutter
And you can basically upload any data you want

Resources