Dinotic
Dinotic

Reputation: 3

Firebase - Adding new data to existing node

I have a child node that stores image array on FB database and need to add more images to existing node without overwriting the old ones. setValue() and updateChildren() methods are removing the existing images. Anyone know how to add more nodes to a existing array?

I need to add more image urls to this node: I need to add more image urls to this node.

Doing this overwrites the old nodes.

Map<String, Object> map = new HashMap<String,Object>();
map.put("postImages", updateUrlStrings);
ref.updateChildren(map);

UPDATE:

Now, I can update and add more data (image urls) into map using transactions. But after transaction completed, database generates multiple copy of datas by itself.


DatabaseReference ref = FirebaseDatabase.getInstance().getReference("posts").child(mPostId);

        ref.child("postImages").runTransaction(new Transaction.Handler() {
            @Override
            public Transaction.Result doTransaction(MutableData mutableData) {

                List<String> list = (List<String>) mutableData.getValue();
                if (list == null) {

                    list = new ArrayList<>();
                }

                list.addAll(updateUrlStrings);

                // Set value and report transaction success
                mutableData.setValue(list);
                return Transaction.success(mutableData);
            }

            @Override
            public void onComplete(DatabaseError databaseError, boolean committed,
                                   DataSnapshot currentData) {
                // Transaction completed
                Log.d(TAG, "postTransaction:onComplete:" + databaseError);
                Log.v(TAG, "postTransaction:onComplete:" + mImageUris.size());
            }
        });


Upvotes: 0

Views: 497

Answers (2)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

Let's first cover why your code overwrites the existing values. While updateChildren() does only update the properties that you specify in the map, it does complete replace the values for those properties with the value in the map. Since you specify a new value for postImages in your map, that value completely replaces the existing value for postImages in the database.

If you want to update a deeper nested child, you can pass its entire path in the key of the map. For example, to add a new URL to the array in your screenshot, you can call:

Map<String, Object> map = new HashMap<String,Object>();
map.put("postImages.3", updateUrlStrings);
ref.updateChildren(map);

But this then requires that you know that the next entry becomes number 3.


Since you're using an array with sequential, numeric indexes to store the URLs, you will need to first read the existing values in order to add one to it. And since that can conflict with other users, you'll need to use a transaction to do so.

So it'd look something like this:

ref.child("postImages").runTransaction(new Transaction.Handler() {
    @Override
    public Transaction.Result doTransaction(MutableData mutableData) {
        List list = mutableData.getValue(List.class);
        if (list == null) {
            list = new ArrayList();
        }

        list.add(updateUrlStrings);

        // Set value and report transaction success
        mutableData.setValue(p);
        return Transaction.success(mutableData);
    }

    @Override
    public void onComplete(DatabaseError databaseError, boolean committed,
    DataSnapshot currentData) {
        Log.d(TAG, "runTransaction:onComplete:" + databaseError);
    }
});

This will work, but is pretty complex for the simple operation. The reason for that is that indexed arrays may be very common in programming, but are not a great concept for massively scalable multi-user cloud databases. For more on this, I highly recommend reading Best Practices: Arrays in Firebase.


The more idiomatic way to store a list of items, is by using Firebase's push() method. This generates a key that is automatically guaranteed to be unique, and always incrementing, no matter how many clients are accessing the database, and it doesn't need to read the existing values to do so.

When using push(), the code to add the URL would look like:

ref.child("postImages").push().setValue(updateUrlStrings);

Upvotes: 2

UDAY  KAIPA
UDAY KAIPA

Reputation: 21

You can add it in by setting

ref.child('NewId').set(map);//NewId =3 in your case.

It depends on your application, what NewId could be, there is way to generate Unique random keys using push

ref.push(map).

https://firebase.google.com/docs/reference/js/firebase.database.Reference#push

Upvotes: 0

Related Questions