我有一个子节点,该子节点将图像数组存储在FB数据库上,并且需要向现有节点添加更多图像,而不会覆盖旧图像。 setValue()和updateChildren()方法将删除现有图像。有谁知道如何向现有阵列添加更多节点?
我需要向该节点添加更多图像网址:
这样做会覆盖旧节点。
Map<String, Object> map = new HashMap<String,Object>();
map.put("postImages", updateUrlStrings);
ref.updateChildren(map);
更新:
现在,我可以使用事务更新并将更多数据(图像url)添加到地图中。但是交易完成后,数据库会自行生成多个数据副本。
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());
}
});
答案 0 :(得分:1)
让我们首先介绍为什么您的代码会覆盖现有值。尽管updateChildren()
仅更新您在地图中指定的属性,但确实用地图中的值替换了这些属性的值。由于您在地图中为postImages
指定了一个新值,因此该值将完全替换数据库中postImages
的现有值。
如果要更新更深的嵌套子级,可以在地图的键中传递其整个路径。例如,要将新的URL添加到屏幕快照中的数组,可以调用:
Map<String, Object> map = new HashMap<String,Object>();
map.put("postImages.3", updateUrlStrings);
ref.updateChildren(map);
但这然后要求您知道下一个条目成为数字3
。
由于您使用的是带有顺序数字索引的数组来存储URL,因此您需要先读取现有值才能向其中添加一个值。并且由于这可能与其他用户发生冲突,因此您需要use a transaction来这样做。
所以看起来像这样:
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);
}
});
这将起作用,但是对于简单的操作而言相当复杂。这样做的原因是索引数组在编程中可能很常见,但对于可大规模扩展的多用户云数据库而言并不是一个好主意。有关更多信息,我强烈建议阅读Best Practices: Arrays in Firebase。
存储项目列表的更惯用的方法是使用Firebase的push()
方法。这样会生成一个密钥,无论有多少客户端正在访问数据库,该密钥都会自动保证是唯一的,并且始终会递增,并且不需要读取现有值即可。
使用push()
时,添加URL的代码如下:
ref.child("postImages").push().setValue(updateUrlStrings);
答案 1 :(得分:0)
您可以通过设置将其添加
ref.child('NewId').set(map);//NewId =3 in your case.
取决于您的应用程序,NewId可能是什么,有一种方法可以使用push生成唯一随机密钥
ref.push(map).
https://firebase.google.com/docs/reference/js/firebase.database.Reference#push