【问题标题】:What is the best way to add data to a list in Firebase Realtime Database将数据添加到 Firebase 实时数据库中的列表的最佳方法是什么
【发布时间】:2019-03-14 02:07:17
【问题描述】:

我正在使用 firebase 实时数据库,并将字符串列表存储在特定的存储引用中。目前,添加一些东西到列表中

我正在执行以下步骤。

  1. 读取数据库子引用
  2. 获取数据快照并检查它是否为空(这意味着首先 时间)
  3. 如果为null,直接设置你的本地列表
  4. 如果dataSnapshot.getValue(); 不为空,则(已存在数据 db,因此需要将新数据附加到它的末尾。) 将远程列表从dataSnapshot.getValue(); 保存到本地变量。

    然后将新数据添加到它的末尾

  5. 现在本地列表包含远程和新的所有项目 项目。将此保存到子参考

下面是我为此编写的代码

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

做一个简单的操作有很多步骤。此外,我一直在从远程提取整个数据并将新数据附加到它。

有什么简单的方法可以做到这一点吗?我尝试使用 'push()' 方法如下

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

但它总是为我添加的值添加一个新键。谁能用更少的代码解释什么是正确的方法?

更新:
我的db结构如下图

【问题讨论】:

  • 请添加您的数据库结构。
  • 它是一个简单的字符串列表层次结构,正如您在代码中看到的那样 root() .child("list") .child(list_id); root() 将返回用户根节点的引用,其中包含一个名为 list 的键它持有一个键值对,键为字符串,值List&lt;String&gt;
  • 基本上root() 会返回用户root 裁判。它在每个日期都有用户 cmets,其中 dateString 是每个列表的键。希望你理解结构
  • 与其解释数据库的外观,不如添加 JSON 格式的结构或至少一个屏幕截图。
  • @AlexMamo 数据库结构图片已添加

标签: android firebase firebase-realtime-database


【解决方案1】:

你给出的解决方案很好,但是为什么要在回调中移除监听器呢? 我会为您编写更简单的代码。请看下面:

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

不要忽略错误。

08-10-18 节点中添加新子节点的最简单方法是仅使用以下代码行,而无需获取整个列表:

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

但更好的解决方案是使用 push() 方法添加而不是列表、地图和子项。所以你的数据库结构应该是这样的:

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

代码应该是这样的:

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

在这种情况下,您不必担心密钥,它不再是数字了。如果没有push() 方法的帮助,您需要获取整个列表,如我的答案第一部分所述,添加新元素并更新数据库中的列表。

【讨论】:

  • 删除了侦听器,因为它将以递归的onDataChange 事件触发结束,因为setValue 将再次导致触发listIdRef 中的ValueEventListener,并且它将无限运行,因为您没有删除监听器
  • @doe 没有必要。您是否尝试过我上面的解决方案?
  • 你的解决方案是一样的吧?修改数据后不用打reference.setValue
  • 这个解决方案只是获取数据,而不是写入数据库。这不是你想要的吗?
  • 您的解决方案与我已经完成的几乎相同。也正如你所说,如果我没有删除监听器,我会递归onDataChange。在您的解决方案中,我们还需要将整个远程数据库值复制到本地,然后上传新列表。我正在寻找一种解决方案,其中 firebase 将始终将数据附加到子节点,以便我们始终仅发送新创建的列表,而无需担心所有那些拉取和附加逻辑
【解决方案2】:

这只是对现有已接受答案的更新,我尝试过并正在努力。这是相同的过程,代码行更少,没有使用ValueEventListener 并使用接受的答案中提到的updateChildren 方法。

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

注意:此代码同步执行数据库写入(Tasks.await 阻塞线程),因此上述代码应仅在后台线程中运行

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    • 2014-12-04
    • 2017-01-23
    相关资源
    最近更新 更多