I have the following Firebase database structure. uIds
is a type of List
. I am trying to add another uId under uIds
with
The Firebase documentation on creating data that scales proposes that you use 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 of the reasons why this data structure works better:
ref.child("uUids").child("user3").setValue(true)
I have started re-iterating to myself: whenever you find yourself doing array.contains("xyz")
, you should probably be using a set instead of an array. The above mapping with "key": true
is an implementation of a set on Firebase.
Some people may think arrays are a more efficient way of storing the data, but in the case of Firebase that is not true:
What you see:
"uIds" : [ "user1", "user2" ]
What Firebase stores:
"uIds" : {
"0": "user1",
"1": "user2"
}
So storing a set is pretty much the same:
"uIds" : {
"user1": true,
"user2": true
}
Adding 2 cents to Frank van Puffelen answer, you can use the key from push operation as a unique identifier of your request. Plus if you use hash map to update child then your DB 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
There is a good old article from the Firebase official blog explaining why we should avoid array in our database : Arrays are Evil
So it's not possible to modify an array without replacing the array. I suggest to change your database structure to this
"requests" : {
"<pushKey1>" : {
"interests" : [ "x" ],
"live" : true,
"uIds" : {
"<pushKey1>" : "user1",
"<pushKey2>" : "user2"
}
},
"<pushKey2>" : {
"interests" : [ "y" ],
"live" : true,
"uIds" : {
"<pushKey1>" : "user2"
}
}
}
To get the pushKey
, you can use push() method (the same as what you have done to each Request
item)
Then the code will be like this if you just want to add a new uid to a request.
String requestKey = "request001";
mDatabase.child("requests").child(requestKey).child("uIds").push().setValue("user2");
Comment here if you have questions, hope this helps :)
Not sure what you mean when you say setValue, etc require you to retrieve existing data. The basic flow for inserting 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 take a look at basic usage guide for Saving Data on Android Firebase.
Update:
Following your comment - I think what you are looking to do can be achieved like this:
You use the push()
method which generates a unique ID every time a new child is added to the specified Firebase reference:
Firebase newRequestRef = mDatabase.child("request").push();
newRequestRef.setValue(newRequest);
This should do it.
I hope this helps.