Add item to list in Firebase Databse

I have the following Firebase database structure. uIds - type List<String> . I am trying to add another uId under uIds with incremental index. setValue() and updateChildren() will require me to get the existing data, and push() will add an element with a randomly generated string as a key instead of the index with the addition. Is there an easier way that does not require existing data to be extracted? Thanks!

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

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

Edit:

Sorry for the aversion. Let me make it clear. Let's say I have the above database and you want to update it to the next.

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

the ishmaelMakitla clause, mDatabase.child("requests").child("request001").setValue(newRequest) , will overwrite "request001" with "newRequest". So I have to get the existing data "request001" and add "user2" to the uIds list. It will be something like this:

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

But I am wondering if this process is needed as I am trying to just add one item to the uIds list.

+6
source share
4 answers

The Firebase documentation for creating scalable data suggests using a different data structure:

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

Here are a few reasons why this data structure works better:

  • each uid can now automatically appear only once. We essentially modeled our data as a collection, rather than using an array.
  • Adding an element is now as easy as ref.child("uUids").child("user3").setValue(true)
  • now you can check if uid exists in your security rules.

I started repeating the iteration myself: whenever you find array.contains("xyz") , you should probably use a set instead of an array. The above mapping to "key": true is a set implementation in Firebase.

Efficiency

Some people might think that arrays are a more efficient way to store data, but this is not the case with Firebase:

What do you see:

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

What stores Firebase:

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

Thus, saving the set is almost the same:

 "uIds" : { "user1": true, "user2": true } 
+12
source

Not sure what you mean when you say setValue etc. you need to restore existing data. The main thread to insert a new record is as follows:

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

You can read the basic guide to using Data Saving on Android Firebase .

Update: After your comment - I think that what you want to do can be achieved as follows: You use the push() method, which generates a unique identifier every time a new child is added to the specified Firebase link:

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

That should do it.

Hope this helps.

+3
source

By adding 2 cents to Frank van Puffelen, you can use the key from the push operation as a unique identifier for your request. Plus, if you use a hash map to update a child, then your database will not be overridden.

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

Result

enter image description here

+1
source

There is a nice old article on the official Firebase blog explaining why we should avoid the array in our database: Arrays of Evil

Thus, it is impossible to change the array without replacing the array. I suggest changing the database structure to

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

To get pushKey , you can use the push () method (just like what you did for each Request element)

Then the code will be like this if you just want to add a new uid to the request.

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

Comment here if you have questions, hope this helps :)

0
source

All Articles