This is my firebase data Structure.
Now what basically I want to do is, first there is the Id:"cbn". I have pushed the Location with push().setValue(gpsData). Now based on this id = "cbn", I want to add new Latitude and Longitude in the Location child exactly like shown in the figure above by using "push(). Till now my code is:
mDatabase = FirebaseDatabase.getInstance().getReference().child("Users");
if (busExists) {
// busId = "cbn"
mDatabase.child(busId).child("Location").push().setValue(gpsData);
}
I know I cannot reference busId as child but how can I access that particular node and push my new data to it.
Any Help?
For new question:
public class Users {
private String bus_id;
private HashMap<String, String> coord = new HashMap<>();
public Users() {
}
public String getBus_id() {
return bus_id;
}
public void setBus_id(String bus_id) {
this.bus_id = bus_id;
}
public HashMap<String, String> getCoord() {
return coord;
}
public void setCoord(HashMap<String, String> coord) {
this.coord = coord;
}
}
I implemented it this way:
mDatabase = FirebaseDatabase.getInstance().getReference();
mDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Users bus = new Users();
bus.setBus_id(ds.getValue(Users.class).getBus_id());
Log.e("bus id: ", bus.getBus_id()+""); // I got NULL
busList.add(bus.getBus_id());
arrayAdapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
You'll need to fire a query to get the push ID of cbn and then add the location from there:
Query query = ref.child("Users").orderByChild("Id").equalTo("cbn");
query.addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot user: snapshot.getChildren()) {
user.getRef().child("Location").push().setValue(...);
The loop in onDataChange() is needed, since there may be multiple child nodes matching the query. If there can only be one child with a specific Id, consider storing the users under that Id.
Users
cbd
Locations:...
With this structure you can add a new location without first querying:
ref.child("Users/cbn/Location").push().setValue(...);
Related
While displaying the recent chats fragment in the application I am fetching my chats from firebase and filtering out the chats by their receiverID and senderID in the chat object to display the recent chats.
The problem says ConcurrentModificationException in ArrayList and it looks like due to the complexity of searching id in the array it occurred, I need a solution to minimize this chat filteration complexity.
// private List<String> stringList; Declaration at top
stringList = new ArrayList<>();
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
databaseReference = FirebaseDatabase.getInstance().getReference("BaatCheet/Chats/");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//userModelList.clear();
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
MessageModel messageModel = dataSnapshot1.getValue(MessageModel.class);
if (messageModel.getSender().equals(firebaseUser.getUid())){
stringList.add(messageModel.getReceiver());
}
if (messageModel.getReceiver().equals(firebaseUser.getUid())){
stringList.add(messageModel.getSender());
}
}
readChat();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
The read chat function
private void readChat() {
userModelList = new ArrayList<>();
databaseReference = FirebaseDatabase.getInstance().getReference("BaatCheet/Users/");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
userModelList.clear();
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()){
UserModel userModel = dataSnapshot1.getValue(UserModel.class);
for (String id: stringList){
if (userModel.getId().equals(id)){
if (userModelList.size() !=0){
for (UserModel userModel1 : userModelList){
if (!userModel.getId().equals(userModel1.getId())){
userModelList.add(userModel);
Log.d("DataAdded",userModel.getId());
} // If the existing list don't have same value for sender and reciever
} // end of inner userModel
} else {
userModelList.add(userModel);
Log.d("DataAdded",userModel.getId());
} // end of else
} // end of userModel id equals string id
} // end of String is loop
} // end of DataSnapshot loop
usersAdapter = new UsersAdapter(userModelList);
recyclerView.setAdapter(usersAdapter);
} // end of onDataChange
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}// end of readChat()
The results would be the recyclerView of recent chats containing the chats which contain messages either send by the sender or receiver to each other.
In the following snippet of code :
for (UserModel userModel1 : userModelList){
if (!userModel.getId().equals(userModel1.getId())){
userModelList.add(userModel);
Log.d("DataAdded",userModel.getId());
} // If the existing list don't have same value for sender and reciever
} //
You are modifying userModelList while iterating through userModelList. This is not allowed and is the cause of ConcurrentModificationException.
There are few ways to simplify the logic, the simplest (albeit not the best) would be to convert this foreach loop into a simple for i loop.
for (int i = 0; i< userModelList.size(); i++) {
UserModel userModel1 = userModelList.get(i);
if (!userModel.getId().equals(userModel1.getId())){
userModelList.add(userModel);
Log.d("DataAdded",userModel.getId());
} // If the existing list don't have same value for sender and reciever
} //
Basically to handle this complexity I am now using separate nodes just for storing the chatLists as such now I don't need to read chats for filtering the recent chats.
The below code is for creating a new node everytime user sends a message it will update the node if the recieverID is different.
dbrefChatList = FirebaseDatabase.getInstance().
getReference("BaatCheet/ChatList/")
.child(senderuserID)
.child(receiveruserID);
dbrefChatList.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (!dataSnapshot.exists()){
dbrefChatList.child("id").setValue(receiveruserID);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
As such ChatList is a Model Class which contains single String called "id" and this id will be used to search in the node.
The below code is for the ChatFragment which fetches the chatList from firebase and set the data to recycler view.
// private List<ChatList> chatList; Declaration at top
chatListList = new ArrayList<>();
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
databaseReference = FirebaseDatabase
.getInstance()
.getReference("BaatCheet/ChatList")
.child(firebaseUser.getUid());
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
chatListList.clear();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
ChatList chatList = snapshot.getValue(ChatList.class);
chatListList.add(chatList);
}
myChatList();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
The function myChatList act as the function of readChat in the problem statement.
private void myChatList() {
userModelList = new ArrayList<>();
databaseReference = FirebaseDatabase.getInstance().getReference("BaatCheet/Users/");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
userModelList.clear();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
UserModel userModel = snapshot.getValue(UserModel.class);
for (ChatList chatList : chatListList){
if (userModel.getId().equals(chatList.getId())){
userModelList.add(userModel);
}
}
}
usersAdapter = new UsersAdapter(userModelList);
recyclerView.setAdapter(usersAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
You can set a flag while traversing the array, after it's done, add it if it doesn't exist yet:
// Display 1 user from chats
for (String id : str_usersList) {
if (user.getId().equals(id)) {
if (userList.size() != 0) {
boolean exists = false;
// If not exists then add
for (User user1 : userList) {
if (user.getId().equals(user1.getId())) {
exists = true;
}
}
if (!exists) {
userList.add(user);
}
} else {
userList.add(user);
}
}
}
I need to list all registered phone number(users) from firebase. I have tried the below solution, but it didn't work fo me. Please help.
DatabaseReference ref =
FirebaseDatabase.getInstance().getReference().child("users");
ref.addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Get map of users in datasnapshot
collectPhoneNumbers((Map<String,Object>)
dataSnapshot.getValue());
}
#Override
public void onCancelled(DatabaseError databaseError) {
//handle databaseError
}
});
}
private void collectPhoneNumbers(Map<String,Object> users) {
ArrayList<Long> phoneNumbers = new ArrayList<>();
//iterate through each user, ignoring their UID
for (Map.Entry<String, Object> entry : users.entrySet()){
//Get user map
Map singleUser = (Map) entry.getValue();
//Get phone field and append to list
phoneNumbers.add((Long) singleUser.get("phone"));
}
System.out.println(phoneNumbers.toString());
}
I need to update few nodes in firebase data which is posted from the server end.Need to update the node "is_done" to 0/1 from the device end.I have tried with different solutions but all became futile i.e it is adding a different node outside the "schedule" node.
Code snippet I have tried
private void updatemultiplefirebasedata() {
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
final DatabaseReference reference = firebaseDatabase.getReference();
Query query = reference.child("schedule").child("22-12-2017").child("route").child("1").child("kid").child("21");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for(DataSnapshot d : dataSnapshot.getChildren()) {
Log.d("Keys",String.valueOf(d.getKey())); //returning all the keys
HashMap<String, Object> result = new HashMap<>();
result.put("is_done", "0");
reference.child(String.valueOf(d.getKey())).updateChildren(result); //update according to keys
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
That's because your database reference still points to the root of your tree. You should assign the desired path to that reference.
Also: You don't need Queries in order to access data directly. You can simply attach a listener to the Database Reference.
private void updatemultiplefirebasedata() {
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
final DatabaseReference reference = firebaseDatabase.getReference().child("schedule").child("22-12-2017").child("route").child("1").child("kid").child("21");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for(DataSnapshot d : dataSnapshot.getChildren()) {
Log.d("Keys",String.valueOf(d.getKey())); //returning all the keys
HashMap<String, Object> result = new HashMap<>();
result.put("is_done", "0");
reference.child(String.valueOf(d.getKey())).updateChildren(result); //update according to keys
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Try this :
reference.child(d.getKey()).updateChildren(result);
remove String.valueOf from child because your key is integer and you are passing it as string so instead of pointing it to same child it will create new key with String "1"
I am trying to display all child "name" located in my database tree. My Database tree I used the Map to do so:
GenericTypeIndicator<Map<String, Object>> m = new GenericTypeIndicator<Map<String, Object>>() {};
Map<String, Object> map = snapshot.getValue(m);
String username = (String) map.get("name");
displayName.setText(username);// Display the name
I am displaying all the data into a recyclerView. But for some reasons instead of getting all names(Eva, smith, princess), I am only one which is the lastest one created "princess" being displayed 3 times in my recyclerView layout(princess, princess, princess). Anyone has any idea what I am doing wrong?
Assuming that you have a node named users in which you have all those uid's, to get all those name, please use the code below. Is the easiest way to achieve this.
DatabaseReference yourRef = FirebaseDatabase.getInstance().getReference().child("users");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String userId = (String) dataSnapshot.getKey();
DatabaseReference userIdRef = FirebaseDatabase.getInstance().getReference().child("users").child(userId);
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String name = (String) dataSnapshot.child("name").getValue();
Log.d("TAG", name);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
userIdRef.addListenerForSingleValueEvent(eventListener);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
yourRef.addListenerForSingleValueEvent(eventListener);
Hope it helps.
The above image is my database structure in firebase. I don't know how to fetch the data inside the child Latlng. How would I fetch it?
In your project, your need to have a POJO representing the "Driver" entity. Something like:
public class Driver {
private String age;
private String busNum;
// etc ...
private HashMap<String, Object> Latlng;
public Driver() {
}
// getters ...
public HashMap<String, Object> getLatlng() {
return Latlng;
}
}
In Firebase, inner objects have to be declared has HashMaps<String, Object>, where the String is the key and the Object can be any other object in your model (in your case a Float I'd bet).
Now, if you want to read some value only once, simply call addListenerForSingleValueEvent method, like this:
FirebaseDatabase.getInstance()
.getReferenceFromUrl(URL_DRIVERS)
.child(driverKey)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Driver driver = dataSnapshot.getValue(Driver.class);
// And here you can access Latlng object
latitude = driver.getLatlng().get("latitude");
longitude = driver.getLatlng().get("longitude");
}
#Override
public void onCancelled(DatabaseError databaseError) {
// handle error ...
}
});
Note: URL_DRIVERS would be your root node url (https://your-project.firebaseio.com/) plus your Driver node location (in your case "Driver")
What I can understand from the screen shot of data you shared that you are pushing values in Driver node, so if I am guessing right, it is not the user id that you can get and pass in code(as mentioned in other answers).
In that scenario you have to get snapshot of Driver node
1.) Create a POJO of Drier entity, Driver.class
public class Driver {
private String age;
private String busNum;
// etc ...
private HashMap<String, Object> Latlng;
public Driver() {
}
// add all getters and setters...
public HashMap<String, Object> getLatlng() {
return Latlng;
}}
In your activity class
DatabaseReference mDatabaseReference = FirebaseDatabase.getInstance().getReference().child("Driver");
mDatabaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println("There are total" + dataSnapshot.getChildrenCount() + " values");
for (DataSnapshot driverSnapshot: dataSnapshot.getChildren()) {
SampleContent content= driverSnapshot.getValue(Driver.class);
System.out.println(content.getLatlng().toString());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Note: I have not run the code there may be syntax errors, pardon me for that.
Also go through https://firebase.google.com/docs/database/android/retrieve-data for more details.
If you just want to know how to get those values one time, then its something like this:
String lat;
String lon;
String userId = // [get userID from firebase]
String mDatabase = // [get database ref from firebase]
mDatabase.child("Driver").child(userId).child("Latlng").addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
lat = dataSnapshot.child("latitude").getValue();
lon = dataSnapshot.child("longitude").getValue();
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "getUser:onCancelled", databaseError.toException());
// ...
}
});