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 }
Related
I am using this way to search for users in firestore database and I think that it is inefficient way , because it give unrelated results , for example if I type 'k' it give me results does not contain 'k' at all like the image below .
var query = firestore
.collection("users")
.where('name', isGreaterThanOrEqualTo: customer)
.get()
.asStream();
any suggestion please ?!
When you are using the following call:
.where('name', isGreaterThanOrEqualTo: customer)
It means that you are searching the database for the documents in which the "name" property holds a value that is greater than the one you are typing. In this particular case, both "Omar" and "Second Omar" are present in the result-set, since each one of them starts with a letter that is alphabetically ordered after "k". In fact, all capital letters are present in alphabetical order after the lower-case letters. Remember that the search is performed lexicographically.
If you are looking for a full-text search, please note that Firestore doesn't provide one. As #Dharmaraj mentioned in his comment, you should use a third-party solution. You can also find more info in my answer from the following posts:
Search by pattern on Cloud Firestore collection
Is it possible to use Algolia query in FirestoreRecyclerOptions?
In my database:
-Users(Top level collection):
---user1(doc):
----------pets(sub collection):
--------------pet1(doc)
--------------pet2(doc)
---user2(doc):
----------pets(sub collection):
--------------pet3(doc)
--------------pet4(doc)
If i have a List of ids: list("pet2", "pet3", "pet4)
Is there a way to do something like this and get a back a List of DocumentsSnapshots?
firestore.collectionGruop("pets")whereIn(FieldPath.documentId(), list)
It works with a root collection but i dont know if this is possible with a collection group
A collection group query is the only place where a filter on FieldPath.documentId() does not work the way you expect. That's because of some details about the way that this token actually works. If you try to this anyway, you will get an error like this:
Invalid query. When querying a collection group by FieldPath.documentId(), the value provided must result in a valid document path, but 'x' is not because it has an odd number of segments.
If you want to do a filter on document IDs in a collection group query, you will need to store the ID of the document as the value of a field in each document. If you use the field called "id", then you can filter on that field like this:
firestore
.collectionGruop("pets")
.whereIn('id', list)
This will give you a different error saying that you need to create an index, and give you a link to do so. After you create that index (it might take some time), you should be good to go.
See also: How to perform collection group query using document ID in Cloud Firestore
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.
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.
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.