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
Related
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();
}
})
I'm trying to execute some code in my addValueEventListener based on conditions of values in database, but when data changes, listener execute conditions based on old data, and at the second try listener perform data which I want to use. however data change listener perform listenr(-1) data. To be more clear, if "disable" or "stop" child exist I don't want to execute the code, but after data are updated and these children not existing, conditions when I call AddMessage method not executing again, but it execute method when I call for the second time, it perform correctly till next update of the data where it start again same issue.
sendMessage.setOnClickListener(new View.OnClickListener() {#Override
public void onClick(View v) {
AddMessage();
}
});
private void AddMessage() {
nListener = RootRef.child("List Ref").child(messageReceiverID).child(messageSenderID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
if (!dataSnapshot.hasChild("disable") && !dataSnapshot.hasChild("stop")) {
HashMap <String,String> chatMessageMap = new HashMap <>();
chatMessageMap.put("from", messageSenderID);
chatMessageMap.put("type", "check");
chatMessageMap.put("content", messageText);
MessagesRef.child(messageReceiverID).push().setValue(chatMessageMap);
RootRef.child("List Ref").child(messageReceiverID).child(messageSenderID).removeEventListener(nListener);
} else {
RootRef.child("List Ref").child(messageReceiverID).child(messageSenderID).removeEventListener(nListener);
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
sendMessage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String stoppedUser;
myDbref = FirebaseDatabase.getInstance().getReference().child("List Ref").child(<UID_OF_RECEIVER_OF_MESSAGE>);
myDbref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
try {
stoppedUser = dataSnapshot.child(<UID_OF_SENDER>).child("stop").getValue().toString();
//Now use if-else statement
if(<UID_OF_RECEIVER> == stoppedUser){
Toast.makeText(getApplicationContext(), "You are blocked.", Toast.LENGTH_LONG).show();
} else {
AddMessage();
}
}catch (Throwable e){
Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Though you can get <UID_OF_SENDER> by using FirebaseUser currentUserUID = FirebaseAuth.getInstance().getCurrentUser();
Make sure you put the value of <UID_OF_RECEIVER> correctly and also correct the database path if needed.
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.
This is my database. I want to check if a particular uid exists before adding so that I can avoid duplicate entries of the same uid. This is my code. It checks if the uid exists and then returns a boolean. which is parsed into an if statement in another method to add the contact. However, this method only returns false, even if the uid already exists in the contacts. Therefore allowing the adding of the same entry.
The method to check if contact exists.
public void addContacts(final String emailInput){
DatabaseReference users;
users = FirebaseDatabase.getInstance().getReference("users");
users.orderByChild("email").equalTo(emailInput).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
final DatabaseReference ref = FirebaseDatabase.getInstance().getReference("users");
for (DataSnapshot emailSnapshot : dataSnapshot.getChildren()) {
String emailData = emailSnapshot.child("email").getValue(String.class);
final String name = emailSnapshot.child("name").getValue(String.class);
String role = emailSnapshot.child("role").getValue(String.class);
if (emailData.equals(emailInput)){
key = emailSnapshot.getKey();
System.out.println(key);
if ((!role.equals(userRole))) {
DatabaseReference contactRef = ref.child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("contacts").child(key);
contactRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (!dataSnapshot.child(key).exists()) {
ContactProfile newContact = new ContactProfile(key, name);
ref.child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("contacts").push().setValue(newContact);
Toast.makeText(Contacts.this, "Contact Added Successfully", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(Contacts.this, "Contact Already Exists", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
else if(key.equals(FirebaseAuth.getInstance().getCurrentUser().getUid())){
Toast.makeText(Contacts.this, "You cannot add yourself",Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(Contacts.this, "Cannot add user. \n They have the same role",
Toast.LENGTH_SHORT).show();
}
}
else {
Toast.makeText(Contacts.this, "Cannot add user. \n User does not exist",
Toast.LENGTH_SHORT).show();
}
}
}
Although i have no idea about firebase , but the problem might occur due to that you are using method inner class so the scope of value is out of this assignment ,and again you are comparing out of the method inner class so the value=1 will not happen it will always be value=0 so condition will never get true.
Try this...
DatabaseReference contactRef = userRef.child("Users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("contacts").child(key);
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()) {
value = 1;
}
}
Data is loaded from Firebase asynchronously. It is easiest to see what this means if you place a few log statements:
System.out.println("Before attaching listener");
contactRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
System.out.println("Got data");
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
System.out.println("After attaching listener");
When you run this code, it prints:
Before attaching listener
After attaching listener
Got data
This is probably not what you expected, but it explains exactly why your code doesn't work: by the time you check if (value.equals(1)){, the onDataChange method hasn't run yet.
As you see there is no way we can return the value from the database. Any return statement outside of onDataChange will run before the data has been loaded. And any return statement we run within onDataChange won't be able to return data to the calling function.
The quickest solution is to move all code that needs the data into the onDataChange method:
private boolean contactExists(final String key){
DatabaseReference userRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference contactRef = userRef.child("users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("contacts").child(key);
contactRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
... do what we need to do is the key exists
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
}
If you want to make the approach a bit more reusable, you can define your own callback interface and pass that into your contactExists. For an example of this, see my answer here: getContactsFromFirebase() method return an empty list
I want to fetch data from inside Firebase to check whether this user exists in database but there's a problem that i can't solve , listener trigger late this is my code :-
if I remove while loop i can't fetch object fast
if I keep while loop i enter infinite loop , i don't know why
why listener don't trigger
DataSnapshot fetched ;
public boolean user_exist(final String user) throws Exception {
users.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
fetched = dataSnapshot ;
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
while (fetched == null){
Log.e("dbController","not fetched yet");
}
return fetched.hasChild(user);
}
Firebase has to fetch the data from database and bring it in your app. This may take time, hence it should be done in background. When you add valueEventListener, the fetching is done in background. You may display a progressBar to show data is still loading, and once data is in hands, do the rest of code:
users.child(user).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
funUserExists();
} else {
funNoUser();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});