Firebase: Check if any element has a specific property value - java

I have the following JSON structure in my Firebase Database:
- users
|
+--- key: 123
| |
| +-----name : Tom
| +-----email: tom#mymail.com
|
+--- key: 456
|
+-----name : Peter
+-----email: peter#othermail.com
Now I want to check if any user with the email tom#mymail.com exists or not.
I thought:
DatabaseReference usersRef = db.getReference("users");
usersRef.orderByChild("email")
.equalTo("tom#mymail.com")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//fires if exists
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
But this only fires if a user exists and not if it doesn't. How to do it properly?

You can use exactly the code you provided. It will fire no matter if it exists or not. You only need to check if the data exists in the onDataChange() method:
DatabaseReference usersRef = db.getReference("users");
usersRef.orderByChild("email")
.equalTo("tom#mymail.com")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()) {
//exists!
}
else {
//does not exist
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I thought this does not work and I could swear I tried it (maybe with an earlier version of Firebase) but it works!

I see two ways of approaching this:
Load the entire list of users and process it on the device (Not recommended if you have a huge number of users, which you probably do). I will not post the code here because I'm affraid beginners will simply copy and paste it and write awful apps...
Create a node containing the emails of users registered (let's call it userEmails):
userEmails
{
"tom#mymail.com":true,
"peter#othermail.com": true
}
Now, in order to check if the user exists or not:
usersRef.child("tom#mymail.com").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()) {
//User exists
}
else
{
//User doesn't exist
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
The downside of this is that you will have to insert data into both nodes when a new user is registered.

Related

How do I get boolean value if given string is child of given firebase location without downloading whole datasnapshot in firebase?

I need to get only true or false value, if a given String is a child of Firebase node, without getting the whole DataSnapshot of the whole node. This is for reducing the cost of Firebase Realtime download.
Firebase database structure
What I had tried:
VillazRef.child(**UID2**).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot)
{
if (dataSnapshot.child(VISIBLE).hasChild("OMBsclV...0X6w2"))
{
bool=true;
}
if (dataSnapshot.child(INVISIBLE).hasChild("OMBsclV...0X6w2"))
{
bool=true;
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
I think these cades VillazRef.child(**UID2**).addListenerForSingleValueEvent return the whole datasnapshot of this location, but I don't want this, its totally a waste of my bandwidth, so
I need only like
if("OMBsclV...0X6w2" is within the VillazRef.child(**UID2**))
{
bool=true;
}
else
{
bool=false;
}
You're almost there. All you need to do is to go a step deeper into your database hierarchy. Assuming that the following line of code:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
Will return "cxhcK ... kj433" being the UID of the logged-in user (UID2), to check if "OMBsc ... 0X6w2" is a child of the "visible" node, then please use the following lines of code:
String uidToSearch = "OMBsc ... 0X6w2";
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference uidToSearchRef = rootRef.child("Villaz")
.child(uid)
.child("visible")
.child(uidToSearch);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()) {
bool = true;
} else {
bool = false;
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("TAG", databaseError.getMessage()); //Don't ignore potential errors!
}
};
uidToSearchRef.addListenerForSingleValueEvent(valueEventListener);
In this way, you only download a single value from the database and not the entire "visible" node. However, since Firebase API is asynchronous, the value of "bool" cannot be simply used outside the "onDataChange()" method. To be able to use that value outside the callback, please check my answer from the following post:
How to return DataSnapshot value as a result of a method?

android firebase db , checking id duplication problem

i want to check id duplication
i want to make id duplication check code.
so i get the id which is typed from user by using sid = id.getText().toString().trim();
and then make json trees FirebaseDatabase.getInstance().getReference().child("users").child("id").setValue("add");
by using child() method ...
and put the value using setvalue() method.
because it was not possible to use ondatachange() method... (i think this method only works when there is data so i put some no useful data) i will remove the value which is in setvalue() method later (is there another method that can be used even though there is no change... i need to check the db contents)
anyway if (data.getValue()==sid) this part
i thought it can check the id ...
but it does not work
12-25 21:06:00.771 6700-6700/com.example.pc.login D/myTag: {id=add}
android log looks like this... id is the child part... and the add is the value that i put
that is the result of the getvalue() method...
summary
:
1. how can i put the id from users to the firebase db
2. how can i get the only id value except child part
when i use getvalue() method. it takes child name and the value that i put
so if the id is exist ...user made ... user should write another...
if not... the firebase db store the id user made...
thank you for reading ... help me...
idcheckbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//store the id user created
sid = id.getText().toString().trim();
FirebaseDatabase.getInstance().getReference().child("users").child("id").setValue("add");
FirebaseDatabase.getInstance().getReference().addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot data: dataSnapshot.getChildren()){
if (data.getValue()==sid) {
Log.d("myTag",""+dataSnapshot.getChildren());
Toast.makeText(MainActivity.this, "aleady exists",Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "you can use this id",Toast.LENGTH_SHORT).show();
FirebaseDatabase.getInstance().getReference().child("users").child("id").setValue(sid);
Log.d("myTag",""+data.getValue());
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
because it was not possible to use ondatachange() method... (i think this method only works when there is data so i put some no useful data)
No onDataChange(DataSnapshot dataSnapshot) method is triggered once when the listener is attached, whether there is data or NOT.
If the database path where the ValueEventListener is attached is empty/null/non-existent than dataSnapshot.exits() will return false.
Hence here can be your final code:
idcheckbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sid = id.getText().toString().trim();
// No need to store the id user created
// FirebaseDatabase.getInstance().getReference().child("users").child("id").setValue("add");
FirebaseDatabase.getInstance().getReference().child(sid).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// sid already exists
} else {
// sid does not exists already
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
By the way your Firebase Database will look something like this:
{
"sid_1": "...",
"sid_2": "..."
}

Search firebase database for Sport instead of Gender

I am working on an application similar to tinder but to help users to find people to play a specific sport with.
I currently have the code searching the database for the gender of the users (that the user can be matched with). However each user in the database has a node that contains all of the sports the user can pick. If the user prefers a sport the value is saved as 'true' and if not, the value is saved as 'false'. The appropriate users are then shown on the app.
A screenshot of the database is shown below:
This is the code I have so far:
public void checkUserSex(){
final FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
DatabaseReference userDb = usersDb.child(user.getUid());
userDb.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
if (dataSnapshot.child("sex"). getValue() != null){
userSex = dataSnapshot.child("sex").getValue().toString();
switch (userSex){
case "Male":
oppositeUserSex = "Female";
break;
case "Female":
oppositeUserSex = "Male";
break;
}
getOppositeSexUsers();
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
public void getOppositeSexUsers(){
usersDb.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot.child("sex").getValue() != null) {
if (dataSnapshot.exists() && !dataSnapshot.child("connections").child("pass").hasChild(currentUId) && !dataSnapshot.child("connections").child("play").hasChild(currentUId) && dataSnapshot.child("sex").getValue().toString().equals(oppositeUserSex)) {
String profileImageUrl = "default";
if (!dataSnapshot.child("profileImageUrl").getValue().equals("default")) {
profileImageUrl = dataSnapshot.child("profileImageUrl").getValue().toString();
}
cards item = new cards(dataSnapshot.getKey(), dataSnapshot.child("name").getValue().toString(), profileImageUrl);
rowItems.add(item);
arrayAdapter.notifyDataSetChanged();
}
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
How do I change it from matching gender to matching the selected sport?
Unfortunately, Firebase Realtime database does not allow a query based on multiple properties. To achieve what you want, you don't need to restructure your database entirely, you just need to change it a little bit. To solve this problem, you need to add a new node for each sport. Every time you add a new user which plays golf, add it also in its corresponding sport node. Your new node should look like this:
Firebase-root
|
--- golfPlayers
|
--- userId1 : true
|
--- userId2 : true
With this structure you can query your database to get only the users who are playing golf. This can be done by attaching a listener on golf node and iterate on the DataSnapshot object.
This practice is called denormalization and is a common practice when it comes to Firebase. For a better understanding, I recommend you see this video, Denormalization is normal with the Firebase Database.
Note, what you are trying to do and cannot be solved using Firebase Realtime database, can be solved using Cloud Firestore. Give it a try.

Android Firebase - retrieve particular value from Firebase realtime database

In my application I want to retrieve a single value from a particular id. The below screenshot is my database structure:
I want to retrieve the count of likes from database.
This is what I have tried:
public String getLikesCount(String USER_ID){
mref = FirebaseDatabase.getInstance().getReference("user").child(USER_ID);
return currentLike;
}
I don't know what to do after this to get likes count. Can anyone help me please?
do the following:
mref = FirebaseDatabase.getInstance().getReference("user").child(USER_ID).child("likes");
mref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String likes = dataSnapshot.getValue(String.class);
//do what you want with the likes
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});

How to create the user if it does not exist?

When the user logon with your google account for the first time in the app, I made this activity to create the user in the database. It's working, but are creating more than one user in the database, and I don't know why.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_account);
mAuth = FirebaseAuth.getInstance();
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
if (firebaseAuth.getCurrentUser() == null) {
goLogInScreen();
} else {
final String userGoogleEmail = firebaseAuth.getCurrentUser().getEmail();
databaseUser.orderByChild("userEmail").equalTo(userGoogleEmail).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
//User already exists
} else {
//Can create new user
String id = databaseUser.push().getKey();
User user = new User(id, userGoogleEmail, null);
databaseUser.child(id).setValue(user);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
};
This is happening because your are using as an identifier the key generated by the push() method and not another identifier and this is actually creating the user again, even if exists in your database.
What i'm recomending you to do, is to change a little bit the logic of saving the data in your database. So in order to solve your problem, i recomand you using in stead of that key, the email address as an identifier, because is also unique. Your database should look like this:
Firebase-database
|
--- Users
|
--- jon#email,com
| |
| --- //data
|
--- jack#email,com
|
--- //data
As you probably see, i have saved the email addreees in the Firebase database using , (comma) and not . (dot).
name#email.com -> name#email,com
This is because Firebase does not allow symbols like . in the key name. So to store the values like this, the encoded email is required. To achieve this, i recomand you using the following methods:
String encodeUserEmail(String userEmail) {
return userEmail.replace(".", ",");
}
String decodeUserEmail(String userEmail) {
return userEmail.replace(",", ".");
}
To verify if a user exists, simply put the a listeenr on the Users node and use exists() method on the dataSnapshot object like this:
DatabaseReference usersRef = usersDatabaseReference.child(userEmail);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (!dataSnapshot.exists()) {
//create user
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
usersRef.addListenerForSingleValueEvent(valueEventListener);
Hope this solves your problem.

Categories

Resources