Reputation: 3
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:
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
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
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