Unable to use .startAt() with datetime in milliseconds - android

I have a very similar problem to this post - Firebase Query filtered by creation time and where date is greater than now
I have my dates stored in a "message" and I want to retrieve all messages after the current time.
This query works:
Query myTopPostsQuery = mFirebaseDatabaseReference.child(MESSAGES_CHILD).orderByChild("time");
this query returns no data:
Query myTopPostsQuery = mFirebaseDatabaseReference.child(MESSAGES_CHILD).orderByChild("time").startAt(System.currentTimeMillis());
This seems like it should work but from the docs I'm wondering if this is a data type problem?

In your query, you need to specify the full path to the child used for ordering:
orderByChild("date/time")
You indicate that your first query works. It may return the number of messages you expect, but if you look at them, you will find they are not ordered. The query processing is forgiving. If it doesn't find a value for the child identified by orderByChild(), it assigns a value of null and orders by these rules.

Related

Error is coming while get query in Android Studio Firestore

While I'm using the below query in Firestore, an error is coming:
Code:
query = database.collection("CustomerViews/Data/Post")
.whereGreaterThanOrEqualTo("postDate", startDate)
.whereLessThanOrEqualTo("postDate", endDate)
.orderBy("postViews", Query.Direction.DESCENDING)
.orderBy("postDate", Query.Direction.DESCENDING)
Error:
Invalid query. You have an inequality where filter (whereLessThan(), whereGreaterThan(), etc.) on field 'postDate'
and so you must also have 'postDate' as your first orderBy() field, but your first orderBy() is currently on field
'postViews' instead.
The error message is quite explicit about the error. You are using both "whereGreaterThan()" and "whereLessThan()" on the "postDate" field, but you aren't first ordering the results based on that field, hence that error. Please remember, that the order of the method calls in Firestore is very important. To solve this, please change your query to:
query = database.collection("CustomerViews/Data/Post")
.orderBy("postDate", Query.Direction.DESCENDING)
.whereGreaterThanOrEqualTo("postDate", startDate)
.whereLessThanOrEqualTo("postDate", endDate)
.orderBy("postViews", Query.Direction.DESCENDING)
And right after that, simply create the corresponding index. That's it.
Edit:
According to your first comment:
By using your code data is coming but "postViews" descending is not happening. Only postDate descending is coming.
Yes, the results will be returned descending according to "postDate". And if two or more elements will have the same "postDate", then only those results will be after that ordered descending according to "postViews". This is how Firestore works.
According to your second comment:
I want the "postViews" in descending order in given date ranges.
Cloud Firestore queries can only sort or filter range on a single field. What you are trying to achieve it's not possible, since you are trying to filter on "postDate" and then order on "postViews".
In the official documentation, there is an example on how not to do it:
Range filter and first orderBy on different fields
citiesRef.whereGreaterThan("population", 100000).orderBy("country"); //Invalid
According to your last comment:
I got the solution for my problem. I have added the below line before attaching the ArrayList to an adapter.
postArrayList.sortByDescending { it.PostViews }
Indeed it will work if you download all documents on the client and to the filtering there, but it will cost you one document read for each document you download.
Based on your sample code, you have an inequality wherein postDate should be initialized first before postViews as the error suggested. This is currently a restriction of orderBy() clause wherein your first ordering must be on the same field.
In addition to #Alex's answer, You may check the links below for similar scenarios
Firestore query order on field with filter on a different field
Firestore "Invalid query" - Am I using Indexing wrong?
Finally, here's a documentation for the limitations of order and limit data with Cloud Firestore.
I got the solution for my problem. I have added below line before attaching the arraylist to an adapter.
postArrayList.sortByDescending { it.PostViews }

Firestore - Use a Where Clause and startAt with different fields

I'm in a bit of a bind creating a query in Firestore's Android SDK. I want to limit documents to only those from the past week to reduce the number of docs, and also filter results using user-supplied text. I'd like to use a whereGreaterThan clause with the created field for the date, and startAt and endAt clauses for the filtering the id field.
However, there is a problem. The SDK requires that the first orderBy clause use the same field as the whereGreaterThan clause. On the other hand, the startAt and endAt also seem to be bound to the first orderBy clause.
Calendar oneWeekAgo= Calendar.getInstance();
oneWeekAgo.add(Calendar.DATE, -7);
Query query = firestore.collection(BuildConfig.FULL_PATH)
.whereGreaterThan("created",oneWeekAgo.getTime())
.orderBy("created", Query.Direction.ASCENDING)
.orderBy("id", Query.Direction.ASCENDING)
.startAt(filter)
.endAt(filter + "z");
Is there a way to bind the .startAt and .endAt to the second orderBy? Or otherwise accomplish the goal of getting filtered docs from firestore created after a certain date?
If I delete the whereGreaterThan and first orderBy clauses, the query gets filtered results from all documents, not just those created in the past week.
This a limitation of the API because Cloud Firestore doesn't support ordering by a different field than the supplied inequality. In this case you should order the data at client side, in this case your Android app. This is explained here too.

Firebase matching substring

I have the JSON structure above
I want to get the list of vehicles where their ids ends with "123"
I had tried to use Query.endAt() method but i'm not sure if i'm using it right or it shouldn't give the required output
Query vehiclesRef;
vehiclesRef = db.getReference("vehicles").orderByKey().endAt("\uf8ff123");
Firebase Database queries can only perform prefix matches, so strings starting with a specific string or starting with a range of string. It is not possible to query for strings ending with a specific value, nor those ending with a range of values.
If you really want to do this within Firebase, consider also storing the reversed strings in the database:
"321_1_0"
"321_3_0"
"654_52_0"
Then you can query for strings starting with 321 with
vehiclesQuery = db.getReference("vehicles").orderByKey().startAt("321").endAt("321\uf8ff");

Not know exception with firebase filters

This code:
var query: Query = store.collection(COLLECTION_USERS)
query = query.whereGreaterThanOrEqualTo("age", filter.startAge).whereLessThanOrEqualTo("age", filter.endAge)
query = query.whereGreaterThanOrEqualTo("start_date", filter.startDate).whereLessThanOrEqualTo("end_date", filter.endDate)
query = query.whereEqualTo("sex", filter.sex)
return query.get()
throw exception: java.lang.IllegalArgumentException: All where filters other than whereEqualTo() must be on the same field. But you have filters on 'age' and 'start_date' how to fix?
Official documentation of Firestore says that range filters on different fields are forbidden. So Firestore allows to chain multiple where() methods to create more specific queries but only on the same field.
To achieve what you want, you need to query your database twice, once for each fiter because you cannot use both methods in the same query.
Another way to make it happen would be to store a special flag that might fit the query, although in real world applications it will almost impossible to store every single way a user might query the data.

Firebase query implementation

If we query data from Firebase on a key for a child node, does it downloads the whole child node and filter data in the application or it downloads the query specific data? i.e. the filtered data
String myUserId = getUid();
Query myTopPostsQuery = databaseReference.child("user-posts").child(myUserId).orderByChild("starCount");
myTopPostsQuery.addChildEventListener(new ChildEventListener() {});
myTopPostsQuery will sort data according to starCount and I will receive data in the addChildEventListener() I want to know that whether this data is being filtered inside my app after receiving or my app downloads only the filtered data from the Firebase.
If you use a filter in your query you will download the query specific data without any operation executed on the client side.
Keep in mind that:
You can only use one order-by method at a time. Calling an order-by method multiple times in the same query throws an error.
You can combine multiple limit or range functions. For example, you can combine the startAt() and endAt() methods to limit the results to a specified range of values.
For any other info take a read here
You get the data already filtered. When you use a query, let say, limitToLast(10) you get only those 10 elements. This is happening also in your case with orderByChild("starCount"). In your SnanpShot will find only those filtered elements. Please visit official doc for more details.
Hope it helps.
Based on the code you pasted here, your query will just retrieve all the posts for the database path user-posts/<id> with an ordered manner which means that there is not filter. But still you will get back all the available posts under the path you are querying. It can be a "semi-filter" as it will find only the posts which include starCount field
The best thing is to filter during your query in order to retrieve back exactly what is needed and not everything as you are doing right now, imagine that this list of posts can be really big so you will have a big issue with performance later.
Read the following section here about sorting & filtering.
https://firebase.google.com/docs/database/admin/retrieve-data#orderbychild
Apart from that consider to add an index in userId field for speeding up your query.

Categories

Resources