0

I have a simple database structure like so:

database jason

I need to remove the value earphone by using its key which is -M-4XBDqv-ve396r5EHm. I have a button for deleting that value, and I want to use this line of code to remove it: mReferenceForListA.child("List A").child("Items").child(key).removeValue().

But how do I get the key for earphone?

I know I can just write mReferenceForListA.child("List A").child("Items").child(-M-4XBDqv-ve396r5EHm).removeValue() to delete earphone straight away, but what if I need to delete other items in the list?

I'll need to pass a specific key into a variable called "key" to delete a specific value. So, again, how could I get a specific key for the value that I want to delete in my current JSON structure?


This is what I tried:

Reading through related posts for days in stackoverflow and I came down to writing the following codes, but I don't think I got the hang of this thing yet and seriously need help. The following codes always delete the whole "List A" node, but in this case I just need to delete one specified value and keep the others intact in the node.

public static DatabaseReference mRootReference = FirebaseDatabase.getInstance().getReference();
public static DatabaseReference mReferenceForListA = mRootReference.child("List A");

deleteButton= findViewById(R.id.delete_button)  

deleteButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {

        mReferenceForListA.child("Items").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                for (DataSnapshot postsnapshot :dataSnapshot.getChildren()) {
                    String key = postsnapshot.getKey();
                    mReferenceForListA.child("Items").child(key).removeValue();
                }

            }

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

            }
        });

    }
});
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Dean
  • 119
  • 5

2 Answers2

2

To delete a node you need to know its complete path. If you only know a value of (a property of) the node, you can run a query to find all nodes that match that value.

Something like:

public static DatabaseReference mRootReference = FirebaseDatabase.getInstance().getReference();
public static DatabaseReference mReferenceForListA = mRootReference.child("List A");
Query query = mReferenceForListA.child("Items").orderByValue().equalTo("earphone");

query.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        for (DataSnapshot snapshot: dataSnapshot.getChildren()) {
            snapshot.getRef().removeValue();
        }
    }

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

The main changes:

  • The above uses a query on orderByValue() on the Items child. This means Firebase searches all child nodes directly under List A/Items and returns the ones whose value matches earphones.
  • It also uses addListenerForSingleValueEvent, so that the delete only runs once, instead of continuously.
  • It uses snapshot.getRef().removeValue() for a much shorter way to remove the node.
  • It implements onCancelled, since you should never ignore errors.
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Unfortunately this is not working and the database is not reacting at all. I even tried to modifiy the Query line into: " Query query = mRootReference.child("List A").child("Items").orderByKey().equalTo("earphone"); ", and the database doesn't bother to budge. I saw other people succeeded with this method but I don't know why this doesn't work on my jason structure. – Dean Feb 02 '20 at 16:27
  • But I noticed that those who succeeded have a different jason structure. For example their values under the "Items" node would be like: "For charging" : "power bank", "For music" : "earphone" , "For time" : "watch". However, mine is like: "random id" : "power bank", "random id" : "earphone" , "random id" : "watch". Note that my values are paired with random ids. That's why I need to get those specific ids to delete the values. – Dean Feb 02 '20 at 16:35
  • 1
    I just noticed I had the wrong method in the code (though I had the write one in the explanation). Since you're trying to match a *value*, you need to call `orderByValue()`. I've updated the code in my answer. – Frank van Puffelen Feb 02 '20 at 16:36
  • Thanks, Frank. Calling orderByValue() actually does the trick. Thanks for the help! – Dean Feb 02 '20 at 17:22
  • Frank, could I ask you an extened question? If I need to prevent submitting duplicate values, could I use and modify the same code you provided? The current "List A" already contains the value "earphone", and I need to prevent another "earphone" from appearing in "List A". I tried replacing "snapshot.getRef().removeValue();" with " if (!snapshot.hasChild("earphone")) { mReferenceForListA.child("Items").push().setValue("earphone"); }", but it's not working. – Dean Feb 02 '20 at 18:02
  • To prevent duplicate values, you need to use those values as the key in a node. See https://stackoverflow.com/questions/35243492/firebase-android-make-username-unique, and probably more from this: https://stackoverflow.com/search?q=%5Bfirebase-realtime-database%5D+unique+value – Frank van Puffelen Feb 02 '20 at 19:56
  • Thank you, Frank. – Dean Feb 03 '20 at 18:12
0

You should iterate through the DataSnapshot as you have done, but you also need to supply it with a condition to delete the entry with a specific value.

for (DataSnapshot postsnapshot : dataSnapshot.getChildren()) {

     if(postsnapshot.child(postsnapshot.getKey()).getValue(String.class)).equals("earphone"){

         mReferenceForListA.child("List A").child("Items").child(postsnapshot.getkey()).removeValue();

     }
}

Let me know if this works as I am trying to write this from memory.

Garren Fitzenreiter
  • 781
  • 1
  • 5
  • 22
  • Thanks, Garren. I got null pointer warnings (marked in yellow) and an error (marked in red) as shown in this image link: https://ibb.co/r2D2zt7 .Then I tried to modify just bit like this: https://ibb.co/yNcBgsh ,but the app crashed with a null pointer fatal expection on this line: "if(postsnapshot.child(key).getValue(String.class).equals("earphone"))". Is there any change I have to make? By the way, the "mReferenceForListA" already points to the path "List A" so I removed child("List A") on the last line of your codes. – Dean Feb 02 '20 at 16:08
  • I found the way to solve it using Frank van Puffelen's method. Still, thanks for the tip, Garren. – Dean Feb 02 '20 at 17:26