Firebase Realtime Database geting User by Email/Name in Android with Java - java

I want to get a User or just a User UID via email or name. Tried to write the query, but I'm getting all users and then iterating through them and then getting the user but I think it's an expensive task. How can I get only one User/Uid from Realtime Database?
This is what I came up with (But don't think is the best way):
DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference("Users");
Query emailQuery = usersRef.orderByChild("email").equalTo(client.getEmail());
emailQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot child : snapshot.getChildren()) {
if (child.getValue(User.class).getEmail().equals(client.getEmail())){
User user = child.getValue(User.class);
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});

According to your last comment:
I have the corresponding details of each user (email, name), and I want to get the UID of one user (no matter which one)
To get a particular user from the database based on a particular email address, the query that you are already using:
Query emailQuery = usersRef.orderByChild("email").equalTo(client.getEmail());
Returns only the users who have the field email set to what client.getEmail() returns. For instance, if client.getEmail() returns tedo#gmail.com then you'll get a single result, according to your screenshot, which is the first one. That being said, the following if statement, doesn't make sense to be used:
if (child.getValue(User.class).getEmail().equals(client.getEmail())){
User user = child.getValue(User.class);
}
Since the key of the user node is represented by the UID, then you should get it like this:
Query emailQuery = usersRef.orderByChild("email").equalTo(client.getEmail());
emailQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot child : snapshot.getChildren()) {
User user = child.getValue(User.class);
String uid = child.getKey();
//Do what you need to do with UID.
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Log.d("TAG", error.getMessage()); //Never ignore potential errors!
}
});
That's the simplest, cheapest way to query the Realtime Database, in which you return only the elements that you are interested in and that satisfy a particular condition.

Related

how do i retrieve a nested object from Firebase?

I am trying to retrieve a nested list of workouts from a Realtime Database and I don't know how to do it.
I made some research and still couldn't really figure out how am supposed to do it.
The Realtime Database JSON file looks like this :
I am looking to retrieve data by workout, for example, if someone presses the workout one button I should retrieve the full workout one object. but I don't know how am supposed to design my query request nor how am supposed to structure my model object that conceives the received data.
As I see in your screenshot, under the "Workout one" node, you have two nested levels of data. So to get all exercises for each day, you have to loop over the children twice:
DatabaseReference db = FirebaseDatabase.getInstance().getReference();
DatabaseReference workoutOneRef = db.child("Fat Loss").child("Workout one");
workoutOneRef.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (task.isSuccessful()) {
for (DataSnapshot daySnapshot : task.getResult().getChildren()) {
for (DataSnapshot exerciseSnapshot : daySnapshot.getChildren()) {
String name = exerciseSnapshot.child("name").getValue(String.class);
Log.d("TAG", name);
}
}
} else {
Log.d("TAG", task.getException().getMessage()); //Never ignore potential errors!
}
}
});
Please also don't forget that the Firebase API is asynchronous. So any code that needs data from the database needs to be inside the onComplete() method, or be called from there. To understand better, I recommend you check the following resource:
How to read data from Firebase Realtime Database using get()?
I think below line code help you.
databaseReference = FirebaseDatabase.getInstance().getReference().child("Fat Loss").child("Workout one").child("day 1")
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
allTaskList.clear();
if (snapshot.exists()) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
//modal class object
AddTODOListModal model = dataSnapshot.getValue(AddTODOListModal.class);
assert model != null;
model.setId(dataSnapshot.getKey());
allTaskList.add(model);
}
adapter = new TODOListAdapter(TODOListHomeActivity.this, allTaskList);
binding.rvTODO.setAdapter(adapter);
}else {
Utils.showToast("No Data Available");
}
Utils.dismissProgressDialog();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Utils.showToast(error.getDetails());
}
});
Reference link :- https://firebase.google.com/docs/database/android/lists-of-data

dataSnapShot.getChildren() returning null

I'm trying to fetch the user details of a particular user using a query:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference
.child("user_account_settings"))
.orderByChild("user_id")
.equalTo(getItem(position).getUser_id());
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d(TAG, "onDataChange: the fetched user id is " + getItem(position).getUser_id());
for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
//do stuff
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Firebase database screenshot
The user id that is fetched is correct according to the database and it clearly has children, but for some reason dataSnapshot.getChildren() is empty thus not allowing me to iterate through the foreach loop.
The problem in your code lies in the fact that the user ID property is called in the database userid, while in your query you are using user_id, which is incorrect. The name of the field in your query must match the name field in the database. To solve this, simply change:
.orderByChild("user_id")
To:
.orderByChild("userid")

How to parse all child fields and find what I need in Firebase Database?

I do password recovery and I need to know if there is a user in the database with the entered E-mail'om. How do I do that? Here is the structure:
For example, the user entered E-mail - goshan164#gmail.com and I need to know if there is such a mail in my database. And if it exists, then find out the uID of the user with such mail. How do I do that?
P.S uId initially I do not know. In the picture uId = zKCTYc1JkROrGxgOZgvm9CvfSU42
You're looking for a Firebase database query, in this case one that compares the child property of each node against the value you're looking for:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("users"); // or whatever your node is
Query query = ref.orderByChild("account").equalTo("goshan164#gmail.com");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot userSnapshot: dataSnapshot.getChildren()) {
System.out.println(userSnapshot.getKey());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
}
For more on this, see the Firebase documentation on ordering an filtering data.

How to compare two children nodes from different references in Android Firebase?

In Firebase I have the "Users" node where I store information about the registered users and I have the "tasks" node with the tasks information created by each user and 3 owners email addresses added to these tasks manually. I am trying to compare the email field from Users with each owners email. If the current user's email is one of the 3 owner emails, then I will show only the tasks where his email is among those.
This is a snippet from my Firebase realtime database:
"Users" :
{"SolD4tqjUJd1Xru3mRliwtoik2A3" :
{ "email" : "x#gmail.com",
"id" : "SolD4tqjUJd1Xru3mRliwtoik2A3",
"name" : "AB",
"phone" : "123456789"
}
},
"tasks" :
{ "-LgrtyuTjd2QpNIhUeEi" :
{ "-Lgsjx1c-E6OU3t1SbhL" :
{ "id" : "-Lgsjx1c-E6OU3t1SbhL",
"owner_one" : "x#gmail.com",
"owner_three" : "y#gmail.com",
"owner_two" : "z#gmail.com",
"projectId" : "-LgrtyuTjd2QpNIhUeEi",
"taskDate" : "2019 / 6 / 5",
"taskDescription" : "dddd",
"taskName" : "ddddd",
"taskstatus" : "Closed",
"userId" : "SolD4tqjUJd1Xru3mRliwtoik2A3"
}
}
}
}
I have tried the following code to get the email from Users and the owners emails from tasks, but I get stuck at comparing the email with email1, email2 and email3.
myTasks = findViewById(R.id.myTasks);
myTasks.setLayoutManager(new LinearLayoutManager(this));
tasks = new ArrayList<>();
UsersRef = FirebaseDatabase.getInstance().getReference().child("Users");
UsersRef.child(currentUserID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
String email = user.getEmail();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
reference = FirebaseDatabase.getInstance().getReference().child("tasks");
reference.addChildEventListener(new ChildEventListener(){
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
//set code to retrieve data and replace layout
for(DataSnapshot dataSnapshot1: dataSnapshot.getChildren()){
Task p;
p = dataSnapshot1.getValue(Task.class);
String email1 = p.getOwner_one();
String email2 = p.getOwner_two();
String email3 = p.getOwner_three();
tasks.add(p);
}
taskAdapter = new TaskAdapter(MyTasks.this, tasks);
myTasks.setAdapter(taskAdapter);
taskAdapter.notifyDataSetChanged();
}
There is no need to create a database call in order to be able to get the email address of the user, you can simply get the email address directly from the FirebaseUser object like this:
String email = FirebaseAuth.getInstance().getCurrentUser().getEmail();
According to your database schema, please note that there is no way you can query your database when you have two nodes with dynamically (pushed) names. There are also no wildcards in Firebase. To solve this, you should reduce the number of children by adding the project's id as a property of your task object. Now, to get all task that corresponde to a specific email address, please use the following query:
reference = FirebaseDatabase.getInstance().getReference().child("tasks");
Query firstQuery = reference.orderByChild("owner_one").equalsTo("x#gmail.com");
This works only with one property. Unfortunately, you cannot query in Firebase realtime database using multiple "WHERE" clauses (in SQL terms). What you can do is to query the database three times, once for every owner property. The second and the third query should look like this:
Query secondQuery = reference.orderByChild("owner_two").equalsTo("x#gmail.com");
Query thirdQuery = reference.orderByChild("owner_three").equalsTo("x#gmail.com");
Please note, that in order to get the desired result, you should use nested queries that might look like this:
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
if(dataSnapshot.exists()) {
//Perform the second query and then the third query
}
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {}
};
firstQuery.addChildEventListener(childEventListener);
However, this can be more easily done in Cloud Firestore, where you can add a property of type array and use whereArrayContains() method like this:
tasksRef.whereArrayContains("owners", "x#gmail.com");

Firebase: Getting specific field from a node based on field in another node

I have been googling from 3 hours now but have not been able to either phrase the search term correctly or there are no good solutions for it. I am using firebase for my android app. It has a structure like following:
The upper one is comments node
I have just displayed the comments using listview.
commentRef1= FirebaseDatabase.getInstance().getReference().child("Comments").child(postKey1);
commentRef1.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
for(DataSnapshot ds: dataSnapshot.getChildren()){
comment1=ds.getValue(Comment.class);
arrayList.add(comment1);
}
commentList.setAdapter(adapter);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
But as with every relational database, I am trying to save just id or uid in comments(table) or node(rather than whole username).
But, now I am having PROBLEM querying or DISPLAYING USERNAME while displaying comments from the users node (i.e display name) as uid only is saved in comments node.
I found some of the methods like doing nested oneventlistener and so on but little bit confused with the complications and effort need for it.
It would have been simple query or nested select in any sql languages.
Can anybody help? How can i retrieve username or specific value in that query. I saw many storing the while username in comments table. I don't think it is right approach.
To get the full_name, you need to do the following:
DatabaseReference ref=FirebaseDatabase.getInstance().getReference();
commentRef1= FirebaseDatabase.getInstance().getReference().child("Comments").child(postKey1);
commentRef1.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
for(DataSnapshot ds: dataSnapshot.getChildren()){
String userid=ds.child("uid").getValue().toString();
ref.child("Users").orderByKey().equalTo(userid).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String fullname=dataSnapshot.child("full_name").getValue().toString();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
You can use nested listener, I guess you want the user to type the comment then click on a button and creates a node for the comment with a uid,post_id,comment.
Then you want to retrieve the comment to display it with the information, so the datasnapshot will be on Comments/postKey1 then you can retrieve the information there(including the uid), then use orderByKey().equalTo(userid) to be able to retrieve the fullname of the user from the node Users
To avoid all of this just add the fullname in the Comments node instead of the userid
https://firebase.googleblog.com/2013/04/denormalizing-your-data-is-normal.html

Categories