Firebase-将新数据添加到现有节点

时间:2020-11-12 13:15:52

标签: android firebase firebase-realtime-database

我有一个子节点,该子节点将图像数组存储在FB数据库上,并且需要向现有节点添加更多图像,而不会覆盖旧图像。 setValue()和updateChildren()方法将删除现有图像。有谁知道如何向现有阵列添加更多节点?

我需要向该节点添加更多图像网址: I need to add more image urls to this node.

这样做会覆盖旧节点。

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());
            }
        });


2 个答案:

答案 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