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.
Related
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 }
This question already has an answer here:
Firebase query if child of child contains a value
(1 answer)
Closed 3 years ago.
I need a firebase query to filter the list based on the value of an array.
if any of the index of GID(Array) contains the given key. e.g my key is YsGMyfLSGRNHxDWQmhpuPRqtxlq1 and one node's GID have that on 0th index and other have that on 1st index. So these two lists need to be returned.
Currently, I can only get the one at 0th index using the code
//userID = YsGMyfLSGRNHxDWQmhpuPRqtxlq1
firebaseDatabase.child("Groups").queryOrdered(byChild: "GID/0").queryEqual(toValue:userID)
When I try to combine the query I am getting errors.
I don't know about your database structure, But I can explain that There is a limitation in Firebase Realtime database that you can only order by 1 child.
So now if we require to order by 2 Childs we can combine 2 nodes and make it 1 node and can apply order by query on it. For example
If we have username & email fields we can make a new field username_email and can apply order by on it.
Like
user: {
username: "john",
email: "john#g.com"
username_email = "john_john#g.com"
}
Now we can write
firebaseDatabase.child("user").queryOrdered(byChild: "username_email").queryEqual(toValue: "john_john#g.com");
There is no way you can filter your groups based on a value that exist within an array. If you want to query your database to get all groups a particular user is apart of, then you should consider augmenting your data structure to allow a reverse lookup. This means that you should add under each user object the groups in which that user is present.
This means that you'll need to duplicate some data, but this is not a problem when it comes to Firebase. This is a quite common practice, which is named denormalization and for that, I recommend you see this video, Denormalization is normal with the Firebase Database.
When you are duplicating data, there is one thing that need to keep in mind. In the same way you are adding data, you need to maintain it. With other words, if you want to update/detele an item, you need to do it in every place that it exists.
However, what you need is actually allowed in Cloud Firestore. Its array-contains operator allow you to filter documents that have a certain value in an array. For more on this topic, please see the following post:
Better Arrays in Cloud Firestore.
I have a users collection with uId, name, photo
I have a visits collection with uId, userId, location
I have a recyclerview in which I want to show the location with the user name and photo
Can I use the reference field type? If so, how will Firestore know to link visits.userId == users.uId ?
Maybe I first need to query all the visits and then query the relevant user but 2 things:
It means querying a lot of times.
I didn't understand how to collect the joined collection into the adapter, which is based on one query?
Please advice
Thanks
current code
visitsList = db.collection("visitsList");
Query query = visitsList.whereEqualTo("userId",prefs.getString("id","")).orderBy("visitDate", Query.Direction.ASCENDING);
FirestoreRecyclerOptions<AVisit> options = new FirestoreRecyclerOptions.Builder<AVisit>().setQuery(query, AVisit.class).build();
adapter = new VisitsListAdapter(options, VisitsListActivity.this);
RecyclerView rv = findViewById(R.id.rvVisitsList);
rv.setHasFixedSize(true);
rv.setLayoutManager(new LinearLayoutManager(this));
rv.setAdapter(adapter);
The code is a simple query from the collection, not sure how to get the name and photo from the userId field in that collection.
Can I use the reference field type?
Yes, you can use a reference field.
If so, how will Firestore know to link visits.userId == users.uId ?
Firestore results always comes from a single collection (at the moment). It does not automatically join the document from the users collection when you're reading from the visits collection. You will have to do this yourself.
That indeed means you'll be executing multiple reads, but it's often not nearly as slow as you may think. See Google Firestore - how to get document by multiple ids in one round trip?
Update: To show data from the user profile in a list of visits, there are two main options:
load the additional user document in populateView or with a custom parseSnapshot implementation.
duplicate the relevant user data in the visits collection (which is quite normal in NoSQL databases). Also see Alex' answer here: indexed query with FirestoreRecyclerAdapter.
In my project i want to fetch all records from table with sort by created_date descending order.
Also i want to add condition of fetch all item not created_by login user.
I have tried many ways but not able to achieve it.
Below is my table structure.
Here is my java code to fetch records from dynamoDB.
Map<String, Condition> filter = new HashMap<String, Condition>();
//filter.put(RealmConstant.Expo.created_by, new Condition().withComparisonOperator(ComparisonOperator.NE).withAttributeValueList(new AttributeValue().withS(userId)));
filter.put(RealmConstant.Expo.created_date, new Condition().withComparisonOperator(ComparisonOperator.LE.toString()).withAttributeValueList(new AttributeValue().withS(""+new Date())));
Expo expo =new Expo();
expo.setCreated_by(userId);
DynamoDBQueryExpression<Expo> queryExpression = new DynamoDBQueryExpression<Expo>();
queryExpression.setHashKeyValues(expo);
queryExpression.setIndexName(AppConstant.DynamoDBTableIndex.created_by_created_date_index);
queryExpression.setConsistentRead(false);
queryExpression.setRangeKeyConditions(filter);
queryExpression.setScanIndexForward(false);
return mapper.query(Expo.class, queryExpression);
As per above code i am getting all records created by me only. I want to fetch all records not created by me.
Also tried .withFilterExpression("created_by <> :val1").withExpressionAttributeValues(eav); but not working. As already question posted. Why is there no **not equal** comparison in DynamoDB queries?
and
DynamoDB: Filter Expression can only contain non-primary key attributes
The short answer is that you can’t fetch *all the items from a DynamoDB table in sorted order, by any attribute. DynamoDB just doesn’t work that way.
Think of DynamoDB as a distributed hash map of lists.
Just the same as you can’t expect to be able to get globally sorted results from such a map of lists, you can’t get them from DynamoDB either.
You can scan the whole table, and even filter, out some unwanted results as you go, but for sorting, you need to do it after you’ve fetched the records.
What you can do is retrieve items that have the same partition key, in order or the sort key.
And you can create an index where you pick an arbitrary attribute as the partition key and another as the sort key but even that approach has some limitations.
The best way to go is to really take some time and think about what you are going to do with the data. Why are trying to retrieve all items from the table in sorted order? Perhaps there is a better way to organize your data such the you din’t need to retrieve all of it.
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.