web-dev-qa-db-ja.com

Firebase Databaseのリストにアイテムを追加する

次のFirebaseデータベース構造があります。 uIdsは_List<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)は、「request001」を「newRequest」で上書きします。したがって、「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に1つのアイテムを追加するだけなので、このプロセスが必要かどうか疑問に思っています。

14
Yun C Han

スケーリングするデータの作成に関するFirebaseのドキュメント では、異なるデータ構造を使用することを提案しています。

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

このデータ構造がうまく機能する理由のいくつかを以下に示します。

  • 各uidは自動的に1回だけ表示されるようになりました。基本的に、配列を使用する代わりに、データを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 
}
_
16

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

これでうまくいくはずです。

これがお役に立てば幸いです。

3
ishmaelMakitla

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

質問がある場合はここにコメントしてください、これが役立つことを願っています:)

2
Wilik

Frank van Puffelenの回答に2セントを追加すると、Push操作のキーをリクエストの一意の識別子として使用できます。さらに、ハッシュマップを使用して子を更新する場合、DBはオーバーライドされません

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

結果

enter image description here

1
Hitesh Sahu