In my app , there is an activity which upon clicking the save button, 2 sets of data in 2 different places should be made by push(), Since in both places an unique id is needed.
I have followed the sample code in the Firebase guide and added the second push
String userId = auth.getCurrentUser().getUid().toString();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
DatabaseReference firstDatabaseRef = reference.child("first");
DatabaseReference secondDatabaseRef = reference.child("second").child(userId);
String key = firstDatabaseRef.child(userId).push().getKey();
First first = new First(firstAmount,key,firstName);
Map<String, Object> firstValues = first.toMap();
String keySecond = secondDatabaseRef.child(key).push().getKey();
Second second = new Second(secondName,secondAmount,keySecond,key);
Map<String, Object> secondValue = second.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/first/" + userId + "/" + key, firstValues);
childUpdates.put("/second/" + userId + "/" + key + "/" + keySecond, secondValue);
reference.updateChildren(childUpdates);
The result that i got for first was exactly as i expected but for second , instead of creating second/<userId>/<key>/<keySecond>/children, i get this :
"second" : {
//userId
"5TQLPlGf4mbcBRKesQwR30fH1L22" : {
//key
"-KL1030IywlNpkTGC7mU" : {
"secondAmount" : "147",
"Key" : "-KL1030IywlNpkTGC7mU",
"secondName" : "secondName",
"keySecond" : "-KL1030PZlHqD_asSR_8",
}
}
}
Instead of having the final children in another unique id, which by the way is recorded in the keySecond, they are all added directly to the key.
This cannot be accepted since every key must have many keySecond.
I hope that i explained my problem correctly.
Please tell me what am i doing wrong.
How should i modify my code or should i reconsider my data structure completely ?
This is a puzzle. I copy/pasted the code you posted and created stubs for First and Second. Running with Firebase 9.0.2 produced the result shown below, which I believe is what you are expecting. Are you running with a different Firebase version? Is it possible the JSON you posted was produced by a different version of the code you posted?
{
"first" : {
// userId
"ypx8RB3eglTBRPeUT7laQVQ1PZQ2" : {
// key
"-KL3rXeYrscFQNrVQnHb" : {
"firstAmount" : "FirstAmount",
"firstKey" : "-KL3rXeYrscFQNrVQnHb",
"firstName" : "FirstName"
}
}
},
"second" : {
// userId
"ypx8RB3eglTBRPeUT7laQVQ1PZQ2" : {
// key
"-KL3rXeYrscFQNrVQnHb" : {
// keySecond
"-KL3rXe_JyY9Vz2U-NES" : {
"Key" : "-KL3rXeYrscFQNrVQnHb",
"keySecond" : "-KL3rXe_JyY9Vz2U-NES",
"secondAmount" : "SecondAmount",
"secondName" : "SecondName"
}
}
}
}
}
When processing the updateChildren(), the Firebase Database loops over the children that you pass and for each key it essentially does a setValue() with the value you passed.
That means that if you have children with overlapping keys, the value of one of those keys will be written last. The order of these is undefined.
In your case it's fairly easy to merge the updates together:
String key = firstDatabaseRef.child(userId).push().getKey();
First first = new First(firstAmount,key,firstName);
Map<String, Object> firstValues = first.toMap();
String keySecond = secondDatabaseRef.child(key).push().getKey();
Second second = new Second(secondName,secondAmount,keySecond,key);
Map<String, Object> secondValue = trans.toMap();
firstValues.put(keySecond, secondValue); // This is the main change
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/first/" + userId + "/" + key, firstValues);
reference.updateChildren(childUpdates);
Related
I have a code in getting the value of a map named Address.
Map<String, Object> map = document.getData();
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getKey().equals("Address")) {
Log.i(TAG, entry.getValue().toString());
}
}
And here is the output
{Street=VP Inting Avenue, HouseNo=0186, Town=Tagbilaran City, Barangay=Poblacion I}
But I want to get the values (0186 VP Inting Avenue Poblacion I Tagbilaran City) only and not including their keys.
I think you're looking for:
Log.i(TAG, document.get("Address.HouseNo") + document.get("Address.Street") +
document.get("Address.Barangay") + document.get("Address.Town"));
If you know the exact path of the field, there is no need to loop over all fields. And with the . you can address nested fields.
Following up on a similliar question like this one, I just want to get an answer if this is a limitation in FirebaseDatabase.updateChildrenor if I do something wrong.
I understand I cannot specify an update for /USER and then specify a different update for /USER/ + getUid() + "/" + "fancy" + "/" + pushKey
If I still need this two updates to be atomic what should I do?
childUpdates.put(USER + "/" + getUid(), map1);
childUpdates.put(USER + "/" + getUid() + "/" + "fancy" + "/" + pushKey, map2);
// Do a deep-path update
ref.updateChildren(childUpdates, new DatabaseReference.CompletionLi....
UPDATE adding clarification:
The values are Strings
this is map1
//
// FAN_OUT - User.LAST_VISITED_ADDRESS
//
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("last_visited_address", "pushKey");
this is map2
//
// FAN_OUT - User.FANCY
//
Map<String, Object> map2 = new HashMap();
map2.put("owner", "a path");
When you run a multi-location update statement, the Firebase Database loops over the map you provide. For each entry it updates the location/key with the value you provided. The order in which the entries are executed is unspecified.
This means that if you have two conflicting keys/paths, it is undetermined what the result will be. E.g.
/path/to/object { name: "Erik Hellberg" }
/path/to/object/id 6820170
If the server would execute the operations in the order I have them above, the result would be:
path
to
object
id : 6820170
name: "Erik Hellberg"
But if it happened to execute them in the reverse order, the result would be:
path
to
object
id : 6820170
Since an indeterministic operation is pretty useless, the Database rejects the update.
Deterministic ways to get the result are:
/path/to/object { id: 6820170, name: "Erik Hellberg" }
And:
/path/to/object/name "Erik Hellberg"
/path/to/object/id 6820170
Since there is no overlap in update paths here, there is no conflict.
How to give user defined key value in push(), instead of unique value created by push?
This is what am currently doing:
User user = new User(Editname.getText().toString(),
Editpid.getText().toString(),Editsem.getText().toString());
mRef.child("users").push().setValue(user);
.push() will create a new item with a unique reference.
You can use updateChildren() to update instead. For example,
User user=new User(Editname.getText().toString(),Editpid.getText().toString(),Editsem.getText().toString());
Map<String, Object> itemValues = user.toMap();
Map<String, Object> childUpdates = new HashMap<>();
// Define the key value here
String username = "yourKeyValueHere";
childUpdates.put("/users/" + username, itemValues);
mDatabase.updateChildren(childUpdates);
You might have to add something similar to the following to your User class.
#Exclude
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("name", name);
result.put("pid", pid);
result.put("sem", sem);
return result;
}
Simplest way is to specify the child key with the child method:
User user = new User(Editname.getText().toString(),
Editpid.getText().toString(),Editsem.getText().toString());
mRef.child("users").child(user.pid).setValue(user);
Where I specify user.pid, you can use whatever unique key you use to identify the user (typically when using Firebase Authentication this would be user.getUid()).
This is one way to do it assuming we want to use the User's name as unique key:
User user = new User(Editname.getText().toString(),
Editpid.getText().toString(),Editsem.getText().toString());
String uniqueKey = user.getName();
//You could use something else for quick reference since two users can have the same name
mDatabaseReference.child("users").child(uniqueKey).push().setValue(user);
I have two nodes from one root and I want to delete the data from both of them in one request. Both sub-nodes has the same key. I tried this:
Firebase firebaseRef = new Firebase(<root_path>);
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put(<path_to_first_node>, key);
childUpdates.put(<path_to_second_node>, key);
listToRemoveRef.updateChildren(childUpdates, null);
But it removed data from only the first node
It looks like you're using the updateChildren function wrong. What you want to do is this
Firebase firebaseRef = new Firebase(<root_path>);
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("<path_to_first_node>" + key, null);
childUpdates.put("<path_to_second_node>" + key, null);
listToRemoveRef.updateChildren(childUpdates);
The second parameter to updateChildren doesn't set the value to null it is an optional completion listener (see documentation). So instead of passing null to it on the last line, you can just omit it.
This is my code for adding records in Firebase. there's variable outside called restauCount valued (int) as 1
public void sendMessage(){
int restauCount = 1;
String identifier ="Restaurant" + restauCount;
Firebase userRef = firebaseRef.child("Caloocan");
EditText nameInput = (EditText) findViewById(R.id.nameTxt);
String name = nameInput.getText().toString();
EditText locInput = (EditText) findViewById(R.id.locationTxt);
String location = locInput.getText().toString();
EditText typeInput = (EditText) findViewById(R.id.typeTxt);
String foodtype = typeInput.getText().toString();
if (!name.equals("")){
Map<String, String> caloocan = new HashMap<String, String>();
caloocan.put("resname", name);
caloocan.put("resloc", location);
caloocan.put("foodtype", foodtype);
Map<String, Map<String, String>> users = new HashMap<String, Map<String, String>>();
users.put(identifier,caloocan);
userRef.setValue(users);
restauCount++;
}
}
When i run the sendessage() again. i will type in the fields and when i click ADD which is the sendMessage it will be added in FireBase , however when i add new data. IT OVERWRITES THE OLD DATA INPUTTED ? HOW CAN I ADD MULTIPLE DATA IN FIREBASE WITHOUT OVERWRITING THE DATA?
restauCount was created to increment the number of Restaurant i inputted,
userRef.push().setValue(users);
The push() method generates a unique key every time a new child is added to the specified Firebase reference
Use
userRef.setValue(users).push();
instead of userRef.setValue(users);
You are using always the same ref
String identifier ="Restaurant" + restauCount;
Firebase userRef = firebaseRef.child("Caloocan");
userRef.setValue(users);
restauCount++;
Check the doc:
Using setValue() in this way overwrites data at the specified location, including any child nodes.
In your case you are overriding the same data for this reason.
You should use the push() method to generate a unique ID every time a new child is added to the specified Firebase reference.
Firebase userRef = firebaseRef.child("Caloocan");
Firebase newRef = userRef.push();
newRef.setValue(users);
//to get the key
String key = newRef.getKey();
you need to update the identifier it stays the same :
int restauCount = 1;
String identifier ="Restaurant" + restauCount;
try something like :
long restauCount = System.currentTimeMillis();
String identifier ="Restaurant" + restauCount;
here each time you send a sendMessage() your identifier got a specific id as the current time in milliseconds + "Restaurant"
if its important to keep int numbers let me know