firebase index query implementation - firebase

Added a query mentioned below and also created the index in firebase but I don't know what happened since yesterday it is not showing data as per this query and if I remove this:- .where('age', isLessThanOrEqualTo:currentUser.ageRange['max']) from the below query then it shows the data other wise no data. Earlier this was working fine with no problem.
I have tried flutter clean but still no success, pls help me out as I want to implement this in project.
query() {
if (currentUser.showGender == 'everyone') {
return docRef
.where('age', isGreaterThanOrEqualTo: currentUser.ageRange['min'])
.where('age', isLessThanOrEqualTo:currentUser.ageRange['max'])
.orderBy('age', descending: false).limit(docLimit);
} else {
return docRef
.where('editInfo.userGender', isEqualTo: currentUser.showGender)
.where('age', isGreaterThanOrEqualTo:currentUser.ageRange['min'])
.where('age', isLessThanOrEqualTo: currentUser.ageRange['max'])
.orderBy('age', descending: false).limit(docLimit);
}
}

I believe the issue might be because of you're trying to run two range queries separately.
You may won't be able to do that as it's one of the limitation of querying.
You can try including both the comparisons in the single query like
.where("age",isGreater... : x, isLess..: y)
You can read about how querying works in firebase here:
https://firebase.google.com/docs/firestore/query-data/queries

Related

Firebase Firestore Getting documents again on query stream

FirebaseFirestore.instance
.collection(
'chats/${site}/conversations/${room.id}/messages')
.orderBy('createdAt', descending: true)
.where("createdAt", isGreaterThan: dateTime )
.snapshots()
.map(
(snapshot) {
So, On the first document that inserted to the firestore, the I get i a snapshot. On the second, the stream return the first and the second,
So the i get -
(Doc A)
(Doc A,Doc B)
(Doc A, Doc B, Doc C)
And so on. Is there a way to get:
(Doc A)
(Doc B)
(Doc C)
?
I reviewed your snippet and it appears you are using a Stream from the snapshot() method of a CollectionReference type. According to the documentation, this will stream events as they happen in Firestore. You mentioned that with each document inserted in Firestore, you also started getting the previous documents that were inserted before, instead of getting only the one which was just inserted (the latest). This might be related to the dateTime variable you are using to filter documents. Since you are using a greater than comparison, any documents created after the time set in the dateTime will be returned from the query. This could explain why your query returns additional documents each time a new one is added with a timestamp after the dateTime variable.
If you would like to get only the latest document added to the database each time, you can make use of a query limiter. I tested the limitToLast method to get only the latest document added and it appears to work in my testing. This method returns the very last document in a query, and in order for this to be the newest you would have to invert the process to order by ascending (oldest first) so that the newest document is at the bottom:
FirebaseFirestore firebase = FirebaseFirestore.instance;
firebase
.collection('users')
.orderBy('createdAt', descending: false) // orders by ascending order, latest document is the last
.limitToLast(1) // gets the last document, you can set how many docs to get
.get()
.then((QuerySnapshot snapshot) {
if (snapshot != null) {
// Data is available
snapshot.docs.forEach((doc) {
print(doc['firstName']);
});
} else {
print("No data found");
}
}
for everyone who reach this issue on 2022, the solution is rather simple.
You can stay with the same query but check the doc changes:
snapshot.docChanges.forEach((docChange) {
final data = docChange.doc.data() as Map;
LimitToLast won't solve your problem if the internet connection was down for a few moments and multiple updates arrived, but docChanges is all the changes since the last snapshot.
Note: You need to ignore the first time because it will return all the docs on the collection at the first time.

how to where query a collectionGroup in firestore flutter?

I need to query a collectionGroup with where clause and While doing it I stumbled on to a thing.
var payData = FirebaseFirestore.instance.collectionGroup("payment").where("balance", isNotEqualTo: 0);
While executing the above code when I tried to print payData it prints Instance of _JsonQuery. How to access the data inside that variable and what's its structure.
I think the above code is incorrect.
var payData = FirebaseFirestore.instance.collectionGroup("payment").where("balance", isNotEqualTo: 0).getDocuments();
After surfing I got through the above code but VSCode says it's an error in getDocuments()
So, What I need is to print the data that is in the variable for the query I used above.
getDocuments() was deprecated in favor of get() in version 0.14.0 of the cloud_firestore package (Release notes). You need to call this method on your Query, i.e. payData.
The get() method returns a Future, so you can use then() as follows:
FirebaseFirestore.instance
.collectionGroup("payment")
.where("balance", isNotEqualTo: 0)
.get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
print(doc["<name_of_a_field_in_the_doc>"]);
});
});
However, most of the times you will use one of the approaches shown in the FluterFire doc: depending on whether you want to read the data once or listening to changes in realtime you will use a FutureBuilder or a StreamBuilder.

How Order data by two field in firebase

How I can order data doc by two field, My app have a stream builder and I want order the data by the time that wrote and if the todo important so there is two field in docs one for time and there is boolen value
i want the data order by the time and if the data important that is mean the boolen true to be in the top of the list of stream and when i add data will show ender it. this the code I used for strem
final FirebaseFirestore firestore;
DataBase({this.firestore});
Stream streamTodos({String uid}) {
try {
return firestore
.collection("homeNeeds")
.doc(uid)
.collection('homeNeeds')
.orderBy('time', descending: true)
.snapshots();
} catch (e) {
return e;
}
}
// i tried to put tow orderBy('time', descending: true).orderBy('pin', descending: true)
and it doesn't work the snap shot return empty
it appears that is not as simple as saying you can or you can not, it depends on your specific case, but most likely you'll have to do it client-side.
There is another question like this one here:
You can use multi_sort: ^3.0.0 in this case.
https://pub.dev/packages/multi_sort
I solved this problem by adding Indexes in cloud firestore and that option allow you to use tow orderby in the same code

How to filter Firebase Documents that are in a list of DocumentReferences?

I'm currently building a social network app using Firebase and Flutter, and I've stumbled onto a bit of a problem. My homepage has two tabs, one that contains all posts on the app in chronological order, and the other that contains the posts of the people you follow. The DocReferences of the people the user follows is inside a list. Currently, the code looks like this:
if (myFollows.isNotEmpty)
for (int j = 0; j < myFollows.length; j++) {
await FirebaseFirestore.instance
.collection('posts')
.orderBy('date', descending: true)
.where('user', isEqualTo: myFollows[j])
.get()
.then((value) {
//code
});
But, as you can see, I create seperate queries for each of the followed users, so the resulted list of posts isn't in chronological order.
So, my question is, if there is a way I could query the post documents where the user variable is contained inside the list myFollows, instead of comparing it to each of its values one by one?
Remove the loop and use whereIn. This should work
if (myFollows.isNotEmpty)
await FirebaseFirestore.instance
.collection('posts')
.orderBy('date', descending: true)
.where('user', whereIn: myFollows) //this line changed
.get()
.then((value) {
//code
);
In your 1st execution, you may need to add a new index... just follow the web link (in error message) that will help create this required index.
May not work if following more than 10 users as this is a built-in limit in Firestore (maximum 10 comparisons).
In that case, there is no built-in solution... you need to keep your loop and append every single query separately... then sort your final list.

How to check if an array in a firestore document is empty?

I'm building out an app in flutter and I want to run a query to determine if the array in my firestore document is empty. Is there a way to do this?
Here is a picture of my data structured in firestore.
I know there is an arrayContains method but I'm not sure on how to check for an empty array. Here is my current code.
_postsStream = await _firestore
.collectionGroup('posts')
.where('timestamp', isGreaterThanOrEqualTo: _start)
.where('timestamp', isLessThanOrEqualTo: _end)
.where('problems', arrayContains: )
.snapshots();
I left the arrayContains: intentionally empty for now. Please advise on how I would go about implementing this feature. Thanks in advance!
An empty array defaults to [] So this is possible by doing the following:
Do not use ' ' for the square brackets
final _database = Firestore.instance;
return _database
.collection('arrays')
.document(arrId)
.where('array', isEqualTo: [])
// .where('array', isNull: true) can be used to check if it's null
.snapshots()
.map(_itemListFromSnapshot);
You cannot do it in firestore currently.
What you can do is.
Create a separate property hasProblems which defaults to false.
If the user try to register a problem, then check the flag hasProblems.
If hasProblems==false, then toggle it to true and add the problem to the list.
else no need to toggle, just add the new problem to the list.
If problems are to be removed later on, then check for the list to get empty.
Once it is empty, then toggle hasProblems back to false.
This way you can achieve what you want-
postsStream = await _firestore
.collectionGroup('posts')
.where('timestamp', isGreaterThanOrEqualTo: _start)
.where('timestamp', isLessThanOrEqualTo: _end)
.where('hasProblems',isEqualsTo: false)
.snapshots();
Maybe you can have other better solutions, but this is the one that came in my mind.
You can follow the solution #mubin986 has given, but once the list gets bigger and bigger, it impacts performance.
Cheers, hope it helps.
There is no way to check with firestore query if an array is empty or not.
But, you can follow these steps:
Query the data with range filters:
_postsStream = await _firestore.collectionGroup('posts')
.where('timestamp', isGreaterThanOrEqualTo: _start)
.where('timestamp', isLessThanOrEqualTo: _end)
.snapshots();
After fetching the data, iterate over all the DocumentSnapshot and check if problems array is empty or not.

Resources