1

I'm trying to retrive the data of the last-child in my Firebase Database.

You can see my Database structure here.

What I would like to do is to add another Records child, that is called like the last-child id-number, increased by 1. So in this specific case, for example, I want to create a child called "3", with all its relative fields (id, months, name, time).

I've tried with the following code, but when I run it, it never enters in the addListenerForSingleValueEvent(), and I don't know why. It doesn't give me any error, but it simply doesn't enter in the method.

String name = Joe;
int months= 5;
long time = 10;

FirebaseDatabase database = FirebaseDatabase.getInstance("db-uri");
DatabaseReference myRef = database.getReference().child("Records");

myRef.limitToLast(1).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        if(dataSnapshot.exists()){

            int last_db_user = dataSnapshot.child("id").getValue(Integer.class);
            int new_user = last_db_user++;

            //The User class is just a class that helps setting the values in the db                    
            User user = new User(new_user, name, months, time);

            String key = String.valueOf(new_user);
            myRef.child(key).setValue(user);
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {

    }

I've also tried writing it like the following but, despite the fact that this time it enters in the addListenerForSingleValueEvent(), it says that it can't execute the toInteger() method because the object is null.

myRef.child("Records").limitToLast(1).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        if(dataSnapshot.exists()){

            int last_db_user = dataSnapshot.child("id").getValue(Integer.class);
            int new_user = last_db_user++;

            //The User class is just a class that helps setting the values in the db                    
            User user = new User(new_user, name, months, time);

            String key = String.valueOf(new_user);
            myRef.child(key).setValue(user);
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {

    }

Any ideas on how can I make this work?

UPDATE

String name = Joe;
int months= 5;
long time = 10;

FirebaseDatabase database = FirebaseDatabase.getInstance("db-uri");
DatabaseReference myRef = database.getReference().child("Records");
       
       
myRef.orderByChild("id").limitToLast(1).addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                if(dataSnapshot.exists()){
                    for (DataSnapshot snapshot: dataSnapshot.getChildren()) {
                        int last_db_user = snapshot.child("id").getValue(Integer.class);
                        int new_user = last_db_user++;

                        //The User class is just a class that helps setting the values in the db
                        User user = new User(new_user, name, months, time);

                        String key = String.valueOf(new_user);
                        myRef.child(key).setValue(user);
                    }
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
                throw databaseError.toException();
            }
        });

With this code I get the following exception:

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.app, PID: 28429 java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference at game.GameLogic$1.onDataChange(GameLogic.java:318) at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database@@19.2.1:75) at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database@@19.2.1:63) at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database@@19.2.1:55) at android.os.Handler.handleCallback(Handler.java:900) at android.os.Handler.dispatchMessage(Handler.java:103) at android.os.Looper.loop(Looper.java:219) at android.app.ActivityThread.main(ActivityThread.java:8393) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)

G_S
  • 35
  • 5

1 Answers1

0

It doesn't give me any error

Well, that might be because you're ignoring errors. Please always implement onCancelled, which at its minimum should be:

public void onCancelled(@NonNull DatabaseError databaseError) { 
    throw databaseError.toException(); 
}

The second problem is that you're not ordering on anything, which makes it unclear what limitToLast(1) actually works on. While this may work, you should always specify an ordering. Here that seems:

myRef.orderByChild("id").limitToLast(1).addListenerForSingleValueEvent(new ValueEventListener() {
    ...

The next problem: when you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.

You need to handle this list in your onDataChange by looping over snapshot.getChildren(). So:

myRef.limitToLast(1).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        for (DataSnapshot snapshot: dataSnapshot.getChildren()) { // 
            int last_db_user = snapshot.child("id").getValue(Integer.class);
            int new_user = last_db_user++;

            //The User class is just a class that helps setting the values in the db                    
            User user = new User(new_user, name, months, time);

            String key = String.valueOf(new_user);
            myRef.child(key).setValue(user);
        }
    }
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks for your help! I implemented all of your suggestions, but now I get this exception: E/AndroidRuntime: "FATAL EXCEPTION: main Process: com.example.unilife, PID: 18542 java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference... " – G_S Sep 02 '21 at 03:47
  • That sounds like it's coming from a different place in the code, so you might want to post a new question with its own [MCVE](http://stackoverflow.com/help/mcve). Before doing that though, definitely check https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it as this is a very common error and troubleshooting is always quite similar. – Frank van Puffelen Sep 02 '21 at 04:01
  • It says that the exception occurs at the line: int last_db_user = snapshot.child("id").getValue(Integer.class); It's basically the same error I was getting in the second version of the code I posted :\ – G_S Sep 02 '21 at 14:43
  • That code was missing the loop that I added in my last snippet. Are you sure you updated the code to also then get the value from the child `snapshot`? – Frank van Puffelen Sep 02 '21 at 15:13
  • I've just updated the question so that you can see how I've written the code now that it gives me the exception. Did I make any mistakes? – G_S Sep 03 '21 at 00:41
  • Thanks. Please edit your question to also show the exact error message and stack trace you get for the latest code. – Frank van Puffelen Sep 03 '21 at 00:47
  • Hmm.... I just don't see how that would happen based on the data you've shown and the code. Can you log `snapshot.getValue()` and include the updated code and its output in your question? – Frank van Puffelen Sep 03 '21 at 02:10
  • Sorry, I'm a beginner in programming... What do you mean by logging `snapshot.getValue()`? How do I do that? – G_S Sep 03 '21 at 03:36