doe
doe

Reputation: 981

What is the best way to add data to a list in Firebase Realtime Database

I'm using firebase realtime db, and I'm storing a list of string in a particular storage reference. Currently, to add something to the list

I'm doing the following steps.

  1. Read the database childreference
  2. get the datasnapshot and check if it is null (which means first time)
  3. if it is null, directly set your local list
  4. if dataSnapshot.getValue(); not null then (already data present in the db, so need to append the new data to th e end of it.) save the remote list from dataSnapshot.getValue(); to a local variable.

    then add the new data to the end of it

  5. now the local list contains all the items in remote as well as new items. save this to the child reference

Below is the code I have written for that

DatabaseReference reference = root()
        .child(userId)
        .child(list_id);
reference.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        reference.removeEventListener(this);
        List<String> value = new ArrayList<>();
        if (dataSnapshot.getValue() == null) {
            value.add(message);
        } else {
            if (dataSnapshot.getValue() instanceof List && ((List) dataSnapshot.getValue()).size() > 0 && ((List) dataSnapshot.getValue()).get(0) instanceof String) {
                value = (List<String>) dataSnapshot.getValue();
                value.add(message);
            }
        }
        reference.setValue(value, (databaseError, databaseReference) -> {
            finish();
        });
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        finish();
    }

     private void finish() {
        Log.e(TAG,"save finished");
    }
});

Thats a lot of steps to do a simple operation. Also , all the time I'm pulling the whole data from remote and appending the new data to it.

is there any easy way to do this? I tried with the 'push()' method as follows

DatabaseReference reference = root()
    .child(userId)
    .child(list_id).push();

But it adds a new key always to the value I add. Can anyone explain what is the proper way to do it with less code?

UPDATE:
My db structure is as shown below

enter image description here

Upvotes: 5

Views: 13982

Answers (2)

doe
doe

Reputation: 981

This is just an update to the existing accepted answer, which I tried and working. This is the same process with less lines of code, without using the ValueEventListener and making use of the updateChildren method as mentioned in the accepted answer.

     DatabaseReference reference = deviceRootReference().child(userId).child(list_id).push();
     Map<String, Object> map = new HashMap<>();
     map.put(reference.getKey(), comment);
     Tasks.await(reference.updateChildren(map));

NOTE: This code performs the db write synchronously (Tasks.await blocks the thread), so the above piece of code should run in a background thread only

Upvotes: 0

Alex Mamo
Alex Mamo

Reputation: 138834

The solution you gave it's very good but why to remove the listener inside the callback? I'll write you the code to be more simpler. Please see it below:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference listIdRef = rootRef.child("list").child(list_id);
ValueEventListener valueEventListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        List<String> list = new ArrayList<>();
        for(DataSnapshot ds : dataSnapshot.getChildren()) {
            String comment = ds.getValue(String.class);
            list.add(comment);
        }
        //Do what you need to do with your list
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        Log.d(TAG, databaseError.getMessage());
    }
};
listIdRef.addListenerForSingleValueEvent(valueEventListener);

Don't ignore errors.

The simplest way in which you can add a new child in your 08-10-18 node, without the need to get the enitire list, would be using only the following lines of code:

Map<String, Object> map = new HashMap<>();
map.put("5", "comment55");
rootRef.child("list").child(list_id).updateChildren(map);

But even a better solution would be to use instead of lists, maps and the children should be added using the push() method. So your database structure should look like this:

Fireabase-root
    |
    --- usr100
          |
          --- 08-10-18
                |
                --- randomId: "comment1"
                |
                --- randomId: "comment2"
                |
                --- randomId: "comment3"
                |
                --- randomId: "comment4"

And the code should look like this:

String key = rootRef.child("list").child(list_id).push().getKey();
Map<String, Object> map = new HashMap<>();
map.put(key, "comment5");
rootRef.child("list").child(list_id).updateChildren(map);

In this case you don't have to worry about the key, which is not a number anymore. Without the help of the push() method, you need to get the entire list, as explained in the first part of my answer, add the new element and the update the list in the database.

Upvotes: 7

Related Questions