How to correctly fetch data from firebase using where clauses and custom filters from firebase using flutter - flutter

Im trying to fetch data using
Stream<List<User>> getUsers(User user) {
return _firebaseFirestore
.collection('users')
// .where('interestedIn', isEqualTo: _selectInterest(user))
.snapshots()
.map((snap) {
return snap.docs.map((doc) => User.fromSnapshot(doc)).toList();
});
}
The filter used in the where clause is as follows
_selectInterest(User user) {
if (user.interestPreference == null) {
return ['HIRING', 'WORK'];
}
return user.interestPreference;
}
In firebase I store interestPreference as an Array with 'HIRING' as the only element in the current user's data, when I try to fetch users with 'HIRING' in their interestedIn which is a string I dont get any data. But when I hardcode the where clause as
.where('interestedIn', isEqualTo: 'HIRING')
I get the data, Can anyone help me solve my dilemma?

From that last query, it sounds like the interestedIn field in your database is a single string value, like interestedIn: "HIRING".
Your current query returns documents where interestedIn is an array with exactly the two values you specify, so interestedIn: ['HIRING', 'WORK']
If you want to return all documents where interested in is either "HIRING" or "WORK", you can use an IN condition:
.where('interestedIn', whereIn: ['HIRING', 'WORK'])
Or with your helper function:
.where('interestedIn', whereIn: _selectInterest(user))

Related

Handling Multiple Optional Conditions in Firestore Queries - flutter

I want to get documents from Firestore with conditions. There are 5 conditions where 4 of them are optional. It depends on user input (the user can enter conditions. depending on the user.)
My problem is that I have to create indexes in Firestore. If I use 5 conditions all time, It's enough 1 index. But, In this situation, Some users use 4 conditions, and someone uses 2,3,1. I don't know how many. So, I have to create many indexes. (more than 20). What can I do about this?
I have an idea for it.
All conditions work every time (1 index), But, If the user does not give value to that condition, That condition give all documents. So, I used this method to success my idea. But there is errors. help me to improve my idea or give me another idea to do this.
Code for my idea:
set a function to Stream of StreamBuilder Widget.
That function's code below:
profession, religion, status etc. values get from user inputs.
Stream<QuerySnapshot> getDataStream(
String religion,
String status,
String profession,
String foods,
String education,
) {
var query = FirebaseFirestore.instance
.collection("users")
.where("ethanicity", isEqualTo: "Test");
// religion
if (religion != "") {
query = query.where("religion", isEqualTo: religion);
}
if (religion == "") {
query = query.where("religion", isNotEqualTo: "");
}
// Status
if (status != "") {
query = query.where("status", isEqualTo: status);
}
if (status == "") {
query = query.where("status", isNotEqualTo: "");
}
// // profession
if (profession != "") {
query = query.where("profession", isEqualTo: profession);
}
if (profession == "") {
query = query.where("profession", isNotEqualTo: "");
}
// // foods
if (foods != "") {
query = query.where("status", isEqualTo: foods);
}
if (foods == "") {
query = query.where("status", isNotEqualTo: "");
}
//education
if (education != "") {
query = query.where("education", isEqualTo: education);
} else {
query = query.where("education", isNotEqualTo: "");
}
return query.snapshots();
}
Problem :
I can use isNotEqualTo multiple times in a single query. Can't use like this.
I know two ways to do this, the scalable and the not so scalable version.
Scalable: Use Algolia plugin as an external service to search, it's worth the time learning as you will have a bunch of power for queries.
The other solution is as per https://firebase.google.com/docs/firestore/query-data/queries#limitations firebase limitation, you can only filter on the same field.
You could create an array field called filters ["status", "religion"] and from there you can use a where in query. Now, this is hard to escalate as you would have to update such an array every time a property changes.

Can't get one document from flutter cloud firestore

I'm trying to get one document by user id from firebase cloud firestore using flutter.
I tried firstly to fetch the data then added a condition to it, but i'm not able to display the data or even print it in the console!
Here is what i've tried so far:
database.dart:
Future<DocumentSnapshot?> getFileByUser(String userId) async {
return FirebaseFirestore.instance
.collection('cartesPro')
.where('cartUserId', isEqualTo: FirebaseAuth.instance.currentUser!.uid)
.get()
.then((value) {
value.docs.forEach((element) {
print(element.id);
});
});
}
ui page:
User? user = FirebaseAuth.instance.currentUser;
showFile() {
final files = DatabaseMethods().getFileByUser(user!.uid);
print(files);
}
and then made the call in a button so I can print the result only! it's returning the documents of the actual user, but I couldn't map the result in order to get the latest in timestamp order!
I appreciate any kind of help, thanks in advance!
If you want to get the most recent document for the user, you should order on the field that has the timestamp and the limit to a single result:
FirebaseFirestore.instance
.collection('cartesPro')
.where('cartUserId', isEqualTo: FirebaseAuth.instance.currentUser!.uid)
.orderBy('timestamp', descending: true)
.limit(1)
.get()
See the Firestore documentation on ordering and limiting data for more on this.

How to filter firebase data using a where clause with FieldPat.documentId

Im trying to retrieve data with
Stream<List<User>> getUsers(User user) {
List<String> userFilter = List.from(user.swipeLeft!)
..addAll(user.swipeRight!)
..add(user.uid!);
return _firebaseFirestore
.collection('users')
.where('interestedIn', isEqualTo: 'HIRING')
.where(FieldPath.documentId, whereNotIn: userFilter)
.snapshots()
.map((snap) {
return snap.docs.map((doc) => User.fromSnapshot(doc)).toList();
});
}
I get an error
An error occurred while parsing query arguments, this is most likely an error with this SDK.
Invalid query. When querying with FieldPath.documentId() you must provide a valid document ID, but it was an empty string.
My data in firebase is structured as follows
How can I fix this?
In firebase you cannot filter with the document id, you can only filter with the fields in the document, a way a simple solution will be to generate a unique id by your self using packages like uuid and then save the document with the id and also save the id inside the document fields then you can filter with the id in the document field

Get all documents from a Firestore collection in Flutter

I tried with different ways but i can't edit the structure of code
//First way
QuerySnapshot querySnapshot = await db.firestoreInstance.collection('user-history').get();
var list = querySnapshot.docs;
print('MY LIST ===== $list');
//Second way
final CollectionReference collectionRef = db.firestoreInstance
.collection(historyCollection);
print('MY SECOND LIST ===== $list');
collectionRef.get().then((qs) {
qs.docs.forEach((element) {
print('MY doc id ${element.id}');
});
});
In my firebase collection(historyCollection) i have four documents but the debugger returns me empty array []. Is there another way to call all documents in certain collection through flutter?
I'm trying to call this method through FutureBuilder component.
My version of firestore is: "cloud_firestore: ^0.16.0+1"
This should do the trick:
Future<List<dynamic>> getCollection(CollectionReference collection) async {
try {
QuerySnapshot snapshot = await collection.get();
List<dynamic> result = snapshot.docs.map((doc) => doc.data()).toList();
return result;
} catch (error) {
print(error);
return null;
}
}
The entire problem was not from these fragments of code. This problem is came out from this that my collections have subcollections. I read about this and i understand that subcollections can live without their ancestors and the only way to access parents is to do this is directly specify the exact path and name of the document. To work this code in my case was needed to add dummy components of my entire set of collections. For more information please look up these two topics:
-> https://firebase.google.com/docs/firestore/using-console
-> Firestore DB - documents shown in italics

How to update a Firestore document after querying in Flutter

I am trying to figure out how to update my document after I query the one I want to update. Here is the code I came up with:
Firestore.instance.collection("Social_Posts").where(data["postTitle"], isEqualTo: "postTitle").where(data["postContent"], isEqualTo: "postContent")
.snapshots()
.listen((event) {print("hh");});
Whenever I perform this query to find the correct document, I would like to update the document by adding a number to it.
It is possible to update the document from inside, The easier way to do that would definitely be to use the documentID and to increment the value Firestore has a special property, FieldValue.increment(1). Using this you can easily increment a field.
Lets say the field in the document you want to increment by 1, is "numberField".
Updated code using async/await style:
onTap: () async {
setState(() {
_title = data["postTitle"];
_content= data["postContent"];
});
print(_title);
print(_content);
QuerySnaphot snapshot = await Firestore.instance.collection("Social_Posts")
.where("postTitle" , isEqualTo: _title)
.where("postContent", isEqualTo: _content)
.getDocuments();
if(snapshot.documents.isNotEmpty)
{
snapshot.documents.forEach((doc){
doc.reference.updateData({"views" : FieldValue.increment(1),});
});
}
}
The numberField will be incremented without needing to make an extra call to know the present value.
EDIT : You were making a mistake in the .where() method
You can do that by using the document id you quired from inside the listen function in your case by using the event.documents[0].documentID assuming that your query returns one document only and then you can call the updateData method from Firestone package
Your code might looks like this:
Firestore.instance.collection("Social_Posts")
.where(data["postTitle"], isEqualTo: "postTitle")
.where(data["postContent"], isEqualTo: "postContent")
.snapshots()
.listen((event) {
Firestore.instance
.collection("Social_Posts")
.document(
event.documents[0].documentID)
.updateData(
updateEvent) //Add here the new object you want to
.whenComplete(() {
// You can add your desire action after the row is updated
}
});
You can check package page for more information https://pub.dev/packages/cloud_firestore
And if you want to check a sample on how to perform CRUD functionalities you can check this repository: https://github.com/sayed3li97/flutter_firestore_crud