Firebase Query startAt() - java

I am using a query and having some trouble. I want retrieve value from 5th to 10th. I try to use startAt () the query just doesn't get anything.
public void read(){
Query query = FirebaseDatabase.getInstance().getReference("values").orderByChild("timestamp").startAt(5).endAt(10);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot data: dataSnapshot.getChildren()){
Value upload = data.getValue(Value.class);
mUploads.add(upload);
adapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(MainActivity.this, "Loading Quote failed", Toast.LENGTH_SHORT).show();
}
});
}

Tl;DR: Firebase database queries are cursor based, and not offset based.
When you call startAt() you have to pass in the value of the timestamp you want to start returning results at. You can't pass in offsets, as you are trying to do now.
You current code:
FirebaseDatabase.getInstance()
.getReference("values")
.orderByChild("timestamp")
.startAt(5)
.endAt(10);
Tells the database to:
Find the node called values under the root.
Order each child node by its timestamp value.
Then find a child node with value 5 and start returning results from there.
Stop returning results once it finds a child node with value 10.
As you can probably see, this won't give you any results, since none of your child nodes have a timestamp value between 5 and 10.
As said: Firebase queries are cursor based, meaning they work on knowing something about the node to start at. While many databases paginate based on offsets, Firebase doesn't and you'll need to know the timestamp value of the node to start at.
For example, if you want to start at the node you have opened in your screenshot, and then return the next 5 results, you'd do:
FirebaseDatabase.getInstance()
.getReference("values")
.orderByChild("timestamp")
.startAt(-1590413110563)
.limitToFirst(5);

Related

Retrieve firebase data within a range of 1 week

I want to retrieve Firebase data within a range of say 1 week. I can query and get data for a day like today, but how about for a range of say 1 week? This is the code that am currenly using for retrieving data for a given day
String mDate = DateFormat.getDateInstance().format(new Date());
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("expenses").child(onlineUserId);
Query query = reference.orderByChild("date").equalTo(mDate);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
myDataList.clear();
for (DataSnapshot snapshot :dataSnapshot.getChildren()){
Data data = snapshot.getValue(Data.class);
myDataList.add(data);
}
todayItemsAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
I cannot find a way of retrieving data for a given range. Someone please help.
The Realtime Database is not designed for complex SQL-like queries.
Not sure if your question refers to grouping results by week. If all you need is a set of results that start and on a certain date and end on another date, you can use startAt(...) and endAt(...) like described in this answer or the spec.
If you need anything more complex than that, you need to
either take all results and filter them in your front end/app code
or use a Cloud Function to do the filtering on the server and
passing the results to the front end.
(Not recommended) You can record the week number (i.e. 45_2020) as a separate field in the document, and filter by that. It's messy and you would have to trust that the front end enters correct info in the field.

Get specific child with same parent as another child Firebase

I am making an Android app in Android Studio and I want to get specific data from the Firebase. I am trying to search through the Firebase Realtime Database to get all of the Users that have a usercode of 1234 and then getting their name. This is how I have it set up in Firebase:
Firebase Setup image link
Since I am searching for the data where the usercode = 1234 it will return (in the datasnapshot) all of the information about Joe and Lily (since they were the two users that had a usercode of 1234), but it shouldn't return information about Kevin. Here is how I did that:
Query getUsers = ref.orderByChild("usercode").equalTo(1234);
getUsers.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
//User with usercode = 1234 exists
} else {
//User with that Usercode doesn't exist
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
The datasnapshot, if converted to a string would have all of Lily and Joe's information I believe.
What I want to do is get the first user's name (Which would be Joe in this case) from that datasnaphot. My code will then use it through a few tests before going to the second user's name(Which would be Lily) and repeating the tests. Also, if there were 100 Users then I would need to repeat it for every one of those 100 that had a user code of 1234, so I probably need something repeatable.
So somehow I need to find the first value of the child's name from all of the Users that have a usercode of 1234 and then repeat until I get all of the names and run the test on all of them.
I am new to Stackoverflow, so please tell me if I am missing any information that would be helpful in answering the question.
---- EDIT ----
I have now figured out how to do this with Firebase Firestore. It has simpler queries and allows you to do more with the results. If anyone else has the same issue that I stated above, Firebase Firestore is something you might want to try out.
When using the following line of code:
Query getUsers = ref.orderByChild("usercode").equalTo("1234");
You are searching through the Users node, all users that have the usercode property set to "1234". This query will always return no results because you are searching for 1234 as a String and not as a number, as it is stored in the database. The correct query should be:
Query getUsers = ref.orderByChild("usercode").equalTo(1234); //No double quotes

Find max value from last 50 nodes from Firebase database

I want to find max value from only last 50 nodes. I used to orderByChild and limitToLast methods but it finds max from all nodes, not only from last 50.
Here my db:
And my code:
database = FirebaseDatabase.getInstance();
reference = database.getReference("sensor");
Query query = reference.orderByChild("hum").limitToLast(50);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot myDataSnapshot : dataSnapshot.getChildren())
{
humTemp = myDataSnapshot.child("hum").getValue().toString();
humMax.setText(humTemp);
}
}
public void onCancelled(DatabaseError firebaseError) {
}
});
So, as you see i try to find max value of hum variable from last 50 nodes.
P.S. New nodes are constantly appearing in the database, so the maximum value should change for every 50 values in realtime
If you want the maximum of the 50 most recent nodes, you're trying to order by two properties:
humidity
the time of the node (or its key)
Firebase Database queries can only order/filter on a single property.
In many cases it is possible to combine the values you want to filter on into a single (synthetic) property. For an example of this and other approaches, see my answer here: http://stackoverflow.com/questions/26700924/query-based-on-multiple-where-clauses-in-firebase. But I don't think that's possible for you.
The best I can think of is to just listen for the last 50 nodes, and then re-ordering them on humidity in the client.

Firebase onDataChanged called a lot of times (without updates) and sometimes with null values

I have the following json tree in my firebase app
--ashWoYViS3SbHtBhLpvStRleBl13
----items
-------- -KxDDW1FYMUOxea5w5ii
------------- description: "gggh"
------------- name: "gggh"
ashWoYViS3SbHtBhLpvStRleBl13 is the userId, obtaineid with FirebaseAuth.getInstance().getUser().getUid();
And -KxDDW1FYMUOxea5w5ii is the key for an item, obtained with the push function before inserting the item in the json tree.
There are more items under the items node, this is only a sample.
Then I want to read all the items to show them in a list in my app. I do the following:
ValueEventListener listener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Item> items= utils.convertChildrenToList(dataSnapshot, Item.class);
getView().setData(customContexts);
getView().showContent();
}
#Override
public void onCancelled(DatabaseError databaseError) {
getView().showError(databaseError.toException(), true);
}
};
Query query = database.getReference("/ashWoYViS3SbHtBhLpvStRleBl13/items")
.orderByKey();
query.addValueEventListener(listener);
At this moment there are 5 items in the list, and after setting the listener with addValueEventListener, I expect to receive the result in onDataChanged only once. What really happens is that I receive infinite calls to onDataChanged every few seconds. The first time the snapshot has the 5 items. The second time the snapshot is empty (null). The third time the snapshot has again the 5 items, and so on, in an infinite loop.
The database is not being updated, because of that I don't understand why I'm becoming more than one callback in onDataChanged. The data is always there, and I don't understand also why the snapshot's value is sometimes null
If I use addListenerForSingleValueEvent instead, then I receive only one result in the callback "onDataChanged". Sometimes the snapshot value is null, sometimes the snapshot has the 5 elements. In any case, it does not solve my problem.
I tried with many versions of the Firebase sdk, from v11.0.2 to firebase 11.4.2, and it happens in all the versions.
The only way to solve the problem I found, is the following.
Instead of registering the listener for the path
"/ashWoYViS3SbHtBhLpvStRleBl13/items", I register a listener for the path
"/some_prefix/ashWoYViS3SbHtBhLpvStRleBl13/items" (and obviously, I save the data using the same prefix too).
Then all works as expected, that is, I receive only on result in the callback "onDataChanged". The snapshot is not null, and I receive the next callbacks only when the data under the items node is really changed.
Or if I use addListenerForSingleValueEvent, then I receive only one callback with all the elements in the node "items".
May you say me what I'm doing wrong here? (because I don't want to use the prefix before the user id).
Thanks in advance.
Every time you want to make a query make the fetched false to make sure that onDatachange read the method but when the method inside the onDataChange want to call onDataChange with accident can't have access because your fetched is true then.
For exemple when you make insertion in onDataChange the method will call them self other time without you calling them.
Boolean fetched = false;
ValueEventListener listener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (fetched == false) {
fetched = true;
List<Item> items = utils.convertChildrenToList(dataSnapshot, Item.class);
getView().setData(customContexts);
getView().showContent();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
getView().showError(databaseError.toException(), true);
}
};
Query query = database.getReference("/ashWoYViS3SbHtBhLpvStRleBl13/items")
.orderByKey();
fetched=false;
query.addValueEventListener(listener);

Removing first value from Firebase reference?

I'm looking for something like this:
final DatabaseReference ref = FirebaseDatabase.getInstance().getReferenceFromUrl("https://myproj.firebaseio.com/groceries");
ref.limitToFirst(1).removeValue();
Unfortunately, ref.limitToFirst(1).removeValue(); doesn't exist, only ref.removeValue() does. I want to remove only the first value! How can I do that? I'm sure it's easy & straightforward.
You can only all removeValue() on a DatabaseReference. Calling limitToFirst(1) returns a Query, which does not implement removeValue().
Calling getRef() on that query also won't work, since Query.getRef() returns the location where you executed the query. In other words limitToFirst(1).getRef().removeValue() will remove the entire location, not just the first child.
To delete a specific child node, you will first need to get a DatabaseReference to that child node. And this requires that you execute the query, because only then will you know what child nodes match the query:
DatabaseReference ref = FirebaseDatabase.getInstance().getReferenceFromUrl("https://myproj.firebaseio.com/groceries");
Query query = ref.limitToFirst(1);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
childSnapshot.getRef().removeValue();
}
}
The loop over getChildren() is needed since a query can potentially match multiple child nodes. While your query will match at most one child node, in general there can be any number of results, so the code handles that.

Categories

Resources