【问题标题】:Add an item to a list in Firebase Database将项目添加到 Firebase 数据库中的列表
【发布时间】:2017-02-10 10:11:45
【问题描述】:

我有以下 Firebase 数据库结构。 uIdsList<String> 的一种。我正在尝试在uIds 下添加另一个带有递增索引的uId。 setValue()updateChildren() 将要求我检索现有数据,push() 将添加一个随机生成的字符串作为键而不是递增索引的项目。有没有更简单的方法不需要检索现有数据?谢谢!

  "requests" : {
    "request001" : {
      "interests" : [ "x" ],
      "live" : true,
      "uIds" : [ "user1" ]  // <---- from this
    },
    "request002" : {
      "interests" : [ "y" ],
      "live" : true,
      "uIds" : [ "user2" ]
    }
  }

--------------------------------

编辑:

抱歉,不清楚。让我详细说明一下。 假设我有上述数据库并想将其更新为以下内容。

  "requests" : {
    "-KSVYZwUQPfyosiyRVdr" : {
      "interests" : [ "x" ],
      "live" : true,
      "uIds" : [ "user1", "user2" ]   // <--- to this
    },
    "-KSl1L60g0tW5voyv0VU" : {
      "interests" : [ "y" ],
      "live" : true,
      "uIds" : [ "user2" ]
    }
  }

ishmaelMakitla 的建议mDatabase.child("requests").child("request001").setValue(newRequest) 将用“newRequest”覆盖“request001”。所以我应该检索“request001”的现有数据并将“user2”添加到列表uIds。它会是这样的:

mDatabase.child("requests").child("request001").addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        Request newRequest = dataSnapshot.getValue(Request.class);
        newRequest.uIds.add("user2");
        mDatabase.child("requests").child("request001").setValue(newRequest);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {}

});

但我想知道这个过程是否有必要,因为我要做的只是将一项添加到列表uIds

【问题讨论】:

  • 我的检索数据是什么意思?一切都是为了更新。请尝试再清楚一点,以便更容易为您提供帮助。
  • 通过检索数据,我的意思是运行一个 ValueEventListener 来读取现有的 uId 列表
  • 但您不必附加侦听器来更新子级。你只需要一个参考。只有当您特别想读取数据时,您才会使用侦听器。

标签: android firebase firebase-realtime-database


【解决方案1】:

当您说 setValue 等要求您检索现有数据时,不确定您的意思。插入新记录的基本流程如下:

private DatabaseReference mDatabase;
// get reference to your Firebase Database.
mDatabase = FirebaseDatabase.getInstance().getReference();
//and here you add a new child to your 'requests' collection
//I am assuming you have a Request model like this..
Request newRequest = new Request(some-params);
mDatabase.child("requests").child(someRequestId).setValue(newRequest);

您可以查看Saving Data on Android Firebase 的基本使用指南。

更新: 根据您的评论 - 我认为您想要做的事情可以这样实现: 您使用 push() 方法,每次将新子项添加到指定的 Firebase 引用时都会生成一个唯一 ID:

Firebase newRequestRef = mDatabase.child("request").push();
newRequestRef.setValue(newRequest);

应该这样做。

我希望这会有所帮助。

【讨论】:

  • 没错!这正是他的问题让我感到困惑的地方。
  • @Han,您似乎只想在插入请求之前先生成 ID - 在这种情况下,您只需使用将返回 Refpush,然后使用此 @ 987654327@ 到 setValue 到新请求。我在更新的答案中添加了这个。
【解决方案2】:

Firebase 官方博客中有一篇很好的旧文章解释了为什么我们应该避免在数据库中使用数组:Arrays are Evil

因此,在不替换数组的情况下无法修改数组。我建议将您的数据库结构更改为此

"requests" : {
    "<pushKey1>" : {
        "interests" : [ "x" ],
        "live" : true,
        "uIds" : {
            "<pushKey1>" : "user1",
            "<pushKey2>" : "user2"
        }
    },
    "<pushKey2>" : {
        "interests" : [ "y" ],
        "live" : true,
        "uIds" : {
            "<pushKey1>" : "user2"
        }
    }
}

要获取pushKey,您可以使用push() 方法(与您对每个Request 项目所做的相同)

那么如果你只是想在请求中添加一个新的uid,那么代码会是这样的。

String requestKey = "request001";
mDatabase.child("requests").child(requestKey).child("uIds").push().setValue("user2");

如果您有任何问题,请在此处发表评论,希望对您有所帮助:)

【讨论】:

  • 我有点困惑。既然我们不喜欢数组,那么为什么会有反对“利益”的数组呢?
【解决方案3】:

Firebase documentation on creating data that scales 建议您使用不同的数据结构:

"requests" : {
  "-KSVYZwUQPfyosiyRVdr" : {
    "interests" : { "x": true },
    "live" : true,
    "uIds" : { 
      "user1": true, 
      "user2": true 
    }
  },
  "-KSl1L60g0tW5voyv0VU" : {
    "interests" : { "y": true },
    "live" : true,
    "uIds" : { 
      "user2": true 
    }
  }
}

以下是这种数据结构更有效的几个原因:

  • 现在每个 uid 只能自动出现一次。我们基本上将我们的数据建模为 set,而不是使用数组。
  • 现在添加项目就像ref.child("uUids").child("user3").setValue(true) 一样简单
  • 您现在可以检查安全规则中是否存在 uid。

我已经开始重复自己:每当你发现自己在做 array.contains("xyz") 时,你可能应该使用集合而不是数组。 上面与 "key": true 的映射是一个实现Firebase 上的一组。

效率

有些人可能认为数组是一种更有效的数据存储方式,但在 Firebase 中并非如此:

你看到了什么:

"uIds" : [ "user1", "user2" ]

Firebase 存储的内容:

"uIds" : {
  "0": "user1",
  "1": "user2"
}

所以存储一个集合几乎是一样的:

"uIds" : { 
  "user1": true, 
  "user2": true 
}

【讨论】:

  • 如果是 web javascript,它将是 ref.child("uUids").child("user3").set(true);
【解决方案4】:

在 Frank van Puffelen 的答案中加 2 美分,您可以使用推送操作中的密钥作为您请求的唯一标识符。另外,如果您使用哈希映射来更新孩子,那么您的数据库将不会被覆盖

 // Create a node on Server and get key
  String requestID = AdminController.getInstance().referenceFromUrl
                        .child(END_POINT_REQUESTS)
                        .push().getKey();

  //use key as ID for your Object which you want to push as unique identifier of your model
  requestToPush.setRequestId(requestID );

 //Add updated Model Object in a Map to update DB instead of over writing
 requestsMap.put(requestID , requestToPush);

 //Update newly created DB nodes with data
   referenceFromUrl
            .child(END_POINT_REQUESTS)
            .updateChildren(productsMap,
                    new DatabaseReference.CompletionListener() {
                        @Override
                        public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {

                            if (databaseError != null) {
                                Log.e(TAG, "Error: Data could not be saved "
                                        + databaseError.getMessage());
                            } else {
                                Log.e(TAG, "Success : Data saved successfully.");
                            }
                        }
                    });

结果

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-24
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多