Exclude documents from firebase query using date - firebase

I have a model of posts which have a post time and expire time like so
class BuyerPost{
..some other properties...
final Timestamp postTime;
final Timestamp expireTime;
My intended outcome is that the expired posts will not be included in my query. If i could delete them from the database automatically the better but I would also work with just excluding them from my query.
I have tried to use the endAt and orderBy to achieve it but it failed
Stream <List<BuyerPost>> get sellerBuyerPosts {
try {
return buyerPostCollection.where('status',isEqualTo: 'available')
.orderBy('expireTime',descending: true)
.endAt([Timestamp.now()])
.snapshots()
.map(yieldSellerBuyerPosts);
}catch(e){
print(e.toString());
return null;
}
}
I also tried filtering on the client side but i got a type operator error because <,> is not available for time stamp
List<BuyerPost> yieldSellerBuyerPosts(QuerySnapshot snapshot) {
try {
return snapshot.documents.map((doc) {
return BuyerPost(
...some properties here...
postTime: doc.data['postTime']?? Timestamp(0,0),
expireTime: doc.data['expireTime']?? Timestamp(0,0),
);
}).where((post) =>
post.expireTime>Timestamp.now()
).toList();
}catch(e){
print(e.toString());
return null;
}
}
Am i using the wrong method or have i just made a slight error somewhere.

Don't use endAt in this query. That's for pagination, which you're not using here. If you want to constrain the range of values for a field, use another "where" filter to specify the range of values for that field:
return buyerPostCollection
.where('status', isEqualTo: 'available')
.where('expireTime', isLessThan: Timestamp.now())
.orderBy('expireTime', descending: true)
.snapshots()

The first method actually worked the only issue is that it does not work along with the stream. The only way you will see an update in post queries is with change of widget state, and you will find expired posts disappeared.

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.

firebase index query implementation

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

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

Error using orderBy and startAfterDocument in a query

When using orderBy and startAfterDocument in the same query, I get the following error:
failed: Status{code=FAILED_PRECONDITION, description=The query requires an index. You can create it here: https://console.firebase.goog...
This error is being caught when I try to receive the next set of documents.
Tried to create an index using the link provided in the error but it's a single index using the 'finalTimeStamp' field is being generated and firestore throws out the following exception.
this index is not necessary, configure using single field index controls
In my single field indexes, the descending index for a collection scope is already enabled.
My code:
if (_lastVisible == null) {
try {
data = await chatList
.document(widget.currentUserId)
.collection('inbox')
.orderBy('finalTimeStamp', descending: true)
.limit(10)
.getDocuments();
} catch (e) {
print('caught error 1');
}
} else {
try {
data = await chatList
.document(widget.currentUserId)
.collection('inbox')
.orderBy('finalTimeStamp', descending: true)
.startAfterDocument(_lastVisible)
.limit(10)
.getDocuments();
} catch (e) {
print('caught error 2');
}
}
The orderBy and startAfter or startAfterDocuments should be performed on the same field.
In my question above I've performed orderBy on the finalTimeStamp field and was using startAfterDocument which considers the document ID while ordering the documents. Hence, firestore throws an error.
You can solve this issue in 2 ways:
You can perform startAfter() on finalTimeStamp field. (Didn't consider this for my case because I though there may be multiple documents with the same finalTimeStamp. Using this could give out wrong results)
I created a chatRef field in my documents referencing the same document. I then created an index in firestore to order my documents by finalTimeStamp first and chatRef later. Now while querying, I performed orderBy() twice on finalTimeStamp and chatRef along with the startAfterDocument().

Flutter firestore plugin can't able to fetch data with combination of where and isEqualTo

I have a collection by name "trips" in Firestore. The data format is something like this
I'm trying to access documents of that Collection by using below code.
First way
try {
Firestore.instance
.collection("trips")
.where("createdByName", isEqualTo: "Suresh")
.snapshots
.listen((data) => print('Firestore response1: ${data.documents}'));
} catch (e){
print('Caught Firestore exception1');
print(e);
}
Second way
try {
Firestore.instance.collection("trips").where("createdByName", isEqualTo: "Suresh").getDocuments().then((data) {
print('Firestore response2: , ${data.documents}');
});
} catch (e){
print('Caught Firestore exception2');
print(e);
}
But, none of the above two ways is working. Don't know what I'm doing wrong.
One thing I've noticed whenever I'm removing the where("createdByName", isEqualTo: "Suresh") part from the query it's working fine. But, the moment I include that part query is returning an empty result.
I'm not sure if the screenshot is accurate but it looks like you have a trip node as well. That would put the hierarchy as trips.trip.createdByName, no? If so, it's likely that the where clause is wrong.
Ok, after two days of breaking my brain for this silly thing... this is the answer to the issue... .where('trip.createdByName', isEqualTo: "Suresh")
And, the full queries are like this...
First way
Firestore.instance.collection('trips')
.where('trip.createdByName', isEqualTo: "Suresh")
.snapshots.listen(
(data){
data.documents.forEach((doc) => print( 'Firestore response1 : ${doc.data.toString()}' ));
}
);
Second way
Firestore.instance.collection("trips")
.where("trip.createdByName", isEqualTo: "Suresh")
.getDocuments().then((string) {
string.documents.forEach((doc) => print("Firestore response2: ${doc.data.toString()}" ));
});
Hope, this will be a help. :)

Resources