I am going to make a simple app and I am completely new to Android development. I want to develop an edit button to save my data in the Realtime Database. This is my code:
holder.edite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final DialogPlus dialogPlus=DialogPlus.newDialog(holder.title.getContext())
.setContentHolder(new ViewHolder(R.layout.dialogcontent))
.setExpanded(true,2100)
.create();
View myView=dialogPlus.getHolderView();
EditText title=myView.findViewById(R.id.hTitle);
EditText description=myView.findViewById(R.id.hDescription);
Button submit=myView.findViewById(R.id.usubmit);
title.setText(myItems.getName());
description.setText(myItems.getAddHomeworkDescription());
dialogPlus.show();
submit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Map<String,Object> map=new HashMap<>();
map.put("name",title.getText().toString());
map.put("addHomeworkDescription",description.getText().toString());
DatabaseReference myRef = getInstance().getReference().child("Homework");
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
// String key = myRef.push().getKey();
myRef.child(uid).child()
.updateChildren(map);
dialogPlus.dismiss();
}
});
}
});
This is how my firebase database looks like
What I want to add into .child() to get highlighted(In the image) Unique id direction. But this unique ID is not always same. It change everythime when user create new one.
You will either have to know the push key (-NN...) value of the node you want to update already, determine it with a query, or loop over all child nodes and update them all.
Update a specific child with a known push key
myRef.child(uid).child("-NNsQO7O9lh0ShefShV")
.updateChildren(map);
Update children matching a specific query
Say that you know you want to update the node with name "test12", you can use a query for that:
myRef.child(uid).orderByChild("name").equalToValue("test12").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot nodeSnapshot: dataSnapshot.getChildren()) {
nodeSnapshot.getRef().updateChildren(map);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
})
Update all children
This is a simpler version of the above, by removing the query condition:
myRef.child(uid).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot nodeSnapshot: dataSnapshot.getChildren()) {
nodeSnapshot.getRef().updateChildren(map);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
})
Related
I want to make a query that checks whether a certain name (President or Secretary) exists inside a database.
The structure of the database is as follows.
I have this code, but its not working. Is there something I'm doing wrong?
mDatabase = FirebaseDatabase.getInstance().getReference();
Query presidentquery = mDatabase.child("validate").child(uid).equalTo("President");
presidentquery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
Candidate p = dataSnapshot1.getValue(Candidate.class);
president.setEnabled(false);
president.setText("Voted Already");
}
}
else{
president.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(Home.this, AllCandidates.class));
finish();
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
It seems you know the exact node you want to load, in which case you don't need an equalTo. Instead you can look up the node with:
Query presidentquery = mDatabase.child("validate").child(uid).child("President");
The rest of your code can stay the same.
I am trying to update my mcustDelivery status, from "Accept" to "Enroute" in Firebase after user press enroute button.
but whenever, I press enroute button, the firebase change to "Enroute" and immediately changes back to "Accept".
This is my setOnClickListener for enroute button.
OrderStatus.Java
enroute.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mDatabase.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
dataSnapshot.getRef().child("mcustDeliveryStatus").setValue("Enroute");
enroute.setImageResource(R.drawable.greenenroute);
deliver.setImageResource(R.drawable.bluedeliver);
enroute.setMaxWidth(266);
enroute.setMaxHeight(150);
deliver.setMaxWidth(266);
deliver.setMaxHeight(150);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
this below code is where i get the the Accepted status on ViewNewOrder.java
accept.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mDatabase.child(getKey()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
dataSnapshot.getRef().child("mcustDeliveryStatus").setValue("Accepted");
Intent orderStatus = new Intent(ViewOrderRequest.this, orderStatus.class);
startActivity(orderStatus);
Toast.makeText(getApplicationContext(),"notification sent to customers",Toast.LENGTH_LONG).show();
//start new activity show root map
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(getApplicationContext(),"not updates",Toast.LENGTH_LONG).show();
}
});
}
});
It's simple you have used addValueEventListener for accepting the request you are changing the value in the same reference. So the addValueEventListener triggered up and again change the value to accept. For writing, data refer firebase docs for read and write
private DatabaseReference mDatabase;
mDatabase = FirebaseDatabase.getInstance().getReference();
mDatabase.child(getKey()).child("mcustDeliveryStatus").setValue("Accepted")
or simple fix change that addValueEventListener to addListenerForSingleValueEvent
I am doing an appointment application, this interface is to show to the user that which doctor they have booked an appointment.
I have already done something like this, now I need to use the theraid that I get to retrieve their name which is in another table in Firebase. Can someone teach me how to do it? Thanks in advance :)
Here is my firebase structure.
Here is the code in Java.
a=new ArrayList<AppointmentObject>();
namelist=new ArrayList<String>();
databaseReference= FirebaseDatabase.getInstance().getReference().child("appointment");
databaseReference.orderByChild("userid").equalTo(userid1).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull final DataSnapshot dataSnapshot) {
for(DataSnapshot dataSnapshot1: dataSnapshot.getChildren()) {
AppointmentObject thera= dataSnapshot1.getValue(AppointmentObject.class);
a.add(thera);
}
adapter=new MyRecyclerviewPAppointment(MainActivityPAppointment.this, a,namelist);
rv.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(getApplicationContext(), "Oh no!", Toast.LENGTH_SHORT).show();
}
});
}
}
Here is the Recyclerview class.
#Override
public void onBindViewHolder(#NonNull final MyRecyclerviewPAppointment.MyViewHolder holder,final int position) {
holder.tdate.setText(alist.get(position).getDate());
holder.ttime.setText(alist.get(position).getTiming());
holder.tname.setText(alist.get(position).getTheraid());
}
#Override
public int getItemCount() {
return alist.size();
}
}
The most direct way is to add an additional listener for each appointment, that then look up the user name for that appointment:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
databaseReference= rootRef.child("appointment");
databaseReference.orderByChild("userid").equalTo(userid1).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull final DataSnapshot dataSnapshot) {
for(DataSnapshot dataSnapshot1: dataSnapshot.getChildren()) {
String theraid = dataSnapshot1.child("theraid").getValue(String.class);
DatabaseReference userRef = rootRef.child("alluser/thera").child(theraid);
userRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot userSnapshot) {
String name = userSnapshot.child("name").getValue(String.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
}
}
adapter=new MyRecyclerviewPAppointment(MainActivityPAppointment.this, a,namelist);
rv.setAdapter(adapter);
}
A few things to consider:
This loads the user name for each appointment, even if there are multiple appointments with the same user. In a more realistic scenario you'll want to keep a list of users you've already loaded, either for each appointment query or for a longer time.
While this load will be pretty fast since Firebase pipelines the requests over its existing connecting, it's still additional complexity on reading data. An alternatively would be to store the user name for each appointment in additional to their UID. This type of data duplication is quite common in NoSQL databases.
So guys, I had the database: Event and User.
When some user has interest in some event clicking the button, this will add a child in eventHasInterest with the user in Event database, and in the database User will add the event that has interest. It's already working, but I need to put a counter to show, how many people has interest, and it's not working, only add once. I need one click, +1, another click -1 on.
btn_interest.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
databaseEvent.child(getKeyEvent()).addListenerForSingleValueEvent( //get the event by key
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
final Event event = dataSnapshot.getValue(Event.class);
user = FirebaseAuth.getInstance().getCurrentUser(); //get the user logged in
if(user != null) {
databaseUser.orderByChild("userEmail").equalTo(user.getEmail()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot userSnapshot: dataSnapshot.getChildren()) {
final User user = userSnapshot.getValue(User.class); // user data logged in
databaseUser.orderByChild("userHasInterest").equalTo(event.getEventId()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (!dataSnapshot.exists()) {
databaseUser.child(user.getUserId()).child("userHasInterest").child(event.getEventId()).setValue(event.getEventId());
databaseEvent.child(event.getEventId()).child("eventAmount").setValue(dataSnapshot.getChildrenCount()+1);
} else {
//event already exists
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
databaseEvent.orderByChild("eventHasInterest").equalTo(user.getUserId()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.exists()){
databaseEvent.child(event.getEventId()).child("eventHasInterest").child(user.getUserId()).setValue(user.getUserId());
} else{
//user already exist
}
}
My firebase:
dataSnapshot.getChildrenCount() does not return the int value of eventAmount, it returns the number of children that eventAmount has. In your case, eventAmount will always return 0 since there is no children of eventAmount. I suggest that instead of using getChildrenCount, get the value of the dataSnapshot, and parse that value into an int. After that, increment that value by 1, and store that value instead.
databaseEvent.child(event.getEventId()).child("eventAmount").setValue(Integer.parseInt(dataSnapshot.getValue().toString()) + 1);
EDIT: As suggested by Frank, storing the value using a transaction is recommended to help avoid concurrent updates. I used this post, as well as the post Frank linked to help write the code.
public void updateCount(DatabaseReference database){
database.runTransaction(new Handler() {
#Override
public Result doTransaction(MutableData mutableData) {
//Currently no value in eventAmount
if(mutableData.getValue() == null){
mutableData.setValue(1);
}
else{
mutableData.setValue(Integer.parseInt(mutableData.getValue().toString()) + 1);
}
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
//Probably log the error here.
}
});
}
So in your "userHasInterest" onDataChange method, call my method above like this.
#Override
public void onDataChange(DataSnapshot dataSnapshot){
if(!dataSnapshot.exists()) {
databaseUser.child(user.getUserId()).child("userHasInterest").child(event.getEventId()).setValue(event.getEventId());
updateCount(databaseEvent.child(event.getEventId()).child("eventAmount")); //New line here
} else {
//event already exists
}
}
i have an application with many types of users like normalUser,PremiumUser
and in order to define that i use their unique UID in firebasedatabase to each one in their category premium or normal
this is my database firebase shape
--users
-----normal
-----premium
so if user choose normal account he will be assigned to normal only
for me this is how to grab his data later when he log in is as follows
if (auth.getCurrentUser() != null) {
finish();
Query q = FirebaseDatabase.getInstance().getReference().child("users").child("normal").equalTo(auth.getCurrentUser().getUid());
Query q2 = FirebaseDatabase.getInstance().getReference().child("users").child("premium").equalTo(auth.getCurrentUser().getUid());
if (q != null) {
q.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
startActivity(new Intent(Login.this, Normal.class));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
} else {
q2.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
startActivity(new Intent(Login.this, Premium.class));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
but looks like the code enter both activities altough for sure this account exists in one of categories only(normal or premium)
i tried using
if (dataSnapshot.getChildrenCount()>0) //none of both activities is entered
if (dataSnapshot != null)//both Activites still entered
if(dataSnapshot.getValue(Premium.class)!=null)//vvvv
if(dataSnapshot.getValue(Normal.class)!=null)//but still none entered
i also tried
Query q = FirebaseDatabase.getInstance().getReference().child("users").child("normal").equalTo(auth.getCurrentUser().getUid());
final Query q2 = FirebaseDatabase.getInstance().getReference().child("users").child("premium").equalTo(auth.getCurrentUser().getUid());
q.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
startActivity(new Intent(Login.this, Normal.class));
}
else {
q2.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
startActivity(new Intent(Login.this, Premium.class));
}
but none of them was entered too
how can i fix that
thanks
Your query will never be null, because you created it just before that. There is no way to know how many results a query has without attaching a listener.
So the closest you can get with your current data structure is to nest the queries:
Query q = FirebaseDatabase.getInstance().getReference().child("users").child("normal").equalTo(auth.getCurrentUser().getUid());
Query q2 = FirebaseDatabase.getInstance().getReference().child("users").child("premium").equalTo(auth.getCurrentUser().getUid());
q.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
startActivity(new Intent(Login.this, Normal.class));
}
else {
q2.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
startActivity(new Intent(Login.this, Premium.class));
}
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
}
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
A more direct way to make this work is to change your data structure so that is also contains the payment status for each user. So also store:
user_payment_status
uid1: "normal"
uid2: "premium"
Then you can simply look up the status for the current user with a single value listener. You'll keep your current list around, since you likely also want to show a list of all premium users somewhere in the app.
Duplicating data in this way is quite common in NoSQL databases.
i fixed it by adding to each user a uid then changed
Query q = FirebaseDatabase.getInstance().getReference().child("users").child("normal").equalTo(auth.getCurrentUser().getUid());
Query q2 = FirebaseDatabase.getInstance().getReference().child("users").child("premium").equalTo(auth.getCurrentUser().getUid());
to the following
Query q = FirebaseDatabase.getInstance().getReference().child("users").child("normal").orderByChild("uid").equalTo(auth.getCurrentUser().getUid());
Query q2 = FirebaseDatabase.getInstance().getReference().child("users").child("premium").orderByChild("uid").equalTo(auth.getCurrentUser().getUid());
i still dont know why the first way is wrong