Problem implementing search on my flutter app through cloud firestore - firebase

I want to implement search on my flutter app through cloud firestore database (by 'NAME' field of documents). I came across with the query below but sadly this query is case sensitive.
If I want to search 'Apple', then I will have to type 'Apple'. Typing 'apple' or 'APplE' won't give any result.
FirebaseFirestore.instance
.collection('test')
.where(
'NAME',
isGreaterThanOrEqualTo: searchVal,
isLessThan: searchVal
.substring(0, searchVal.length - 1) +
String.fromCharCode(searchVal
.codeUnitAt(searchVal.length - 1) +
1),
)
.snapshots()
Please suggest any way to make this searching efficient and not case-sensitive.

According to this related thread, Firestore cannot currently perform case-insensitive queries. In this case, the comment on your post applies, so you should create an alternate name field in Firestore that contains all lower case names. From the client side, all queries should be made lower case with a function such as toLowerCase() so that letter cases completely match on both ends.

Related

Flutter Firebase whereQuery in collectionGroup

Why I cant use whereQuery in collectionGroup.
When I use whereQuery like that;
Query colRef = _firestore.collection("users");
colRef = colRef.where("name", isEqualTo: widget.name);
Its working, but when I use whereQuery like that;
Query colRef = _firestore.collectionGroup("users");
colRef = colRef.where("name", isEqualTo: widget.name);
Its not working, while geting the data, I query whether there is an error by using hasError and if else, and I get an error. and I must use collectionGroup while getting data from firebase.
Is there a solution to use whereQuery in collectionGroup?
Firestore Index Settings
I guess I need to somehow enable the disabled options here, but I don't know how to do it.
In summary I want all users in the application to have access to all kinds of data that I specify in the collection Group.
I need to set the composite and exemption part at the same time, when I set both parts according to the paths I want to query, the problem was solved.

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

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)});
});
}),

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 search document(s) from a collection based on a Field in Firestore database?

I'm working on a React Native application and I'm fetching profiles from a firebase collection.
And I want to add a search functionality where when I enter even the first 1 or 2 (or more) alphabets of a username and press the search button.
I should be able to fetch usernames starting with those 1 or 2 alphabets.
I did check Cloud Firestore queries but couldn't find one for my problem.
UPDATED QUESTION:
In the above code, I'm adding the below code as answered by Renaud Tarnec.
let queries = hashes.map(hash => rangeQueryParams(hash))
.map(range => profiles.where('hash', '>=', range.start).where('hash', '<', range.end)
.orderBy('displayName') // displayName is the name of Field here
.startAt(searchString)
.endAt(searchString + '\uf8ff')
.get());
But this doesn't seems to work. I guess it's because range filter and orderBy are on different fields here.
You should use a combination of orderBy(), startAt() and endAt(), see the documentation here: https://firebase.google.com/docs/firestore/query-data/order-limit-data?authuser=0
var searchString = 'Sh' //Example of value
firebase
.firestore()
.collection('yourCollectioName')
.orderBy('username')
.startAt(searchString)
.endAt(searchString + '\uf8ff')
.get()
.then(...)
The character \uf8ff used in the query is after most regular characters in Unicode, therefore the query matches all values that start with searchString.
An approach for full text search recommended by Firebase is to use Algolia https://firebase.google.com/docs/firestore/solutions/search
Using Firestore’s queries with start at and end at with an ordered collection certainly work. If you have a need for full text search within your app elsewhere that requires spelling tolerance etc for example then moving to Algolia is worth considering instead of using compound firestore queries

Firestore error - query requires an index but indexes might not be feasible?

I have a database of items and need to find the ones with matching tags and fetch them 10 at a time (or any given number).
I've tried the following:
(await admin
.firestore()
.collection('media')
.orderBy('id')
.where('descriptions.tagSet.' + 'Test', '==', true)
.where('descriptions.tagSet.' + 'Test2', '==', true)
.startAt(start)
.limit(10)
.get()).docs;
At first I got an error about no index existing for 'id' so I created one using the link Firestore gave me.
However the next error I got was that there's no composite index for descriptions.tagSet.Test.
Unfortunately tags can be any arbitrary number of things, it doesn't seem feasible to have indexes for each possible tag (unless there's a quick programmatic way to create one?).
I'm not sure how to solve this issue, it seems like something which should be simple enough.

Resources