Retrieve Java object by ID from Firebase - java

I am writing an Android app and I am trying to retrieve an object of the class User.java by ID from its Firebase pertinent table. I would like to know how to get it from Java side, as long as I tried the examples stated in Firebase Official docs but none of them is working for me.
Taking this SO question as example, I want a method with the following interface:
public User readUser(String userId);
In other words, I want to execute:
readUser(-lnnROTBVv6FznK81k3n)
and retrieve the associated User object
Thanks
--------------------------------------------------------------EDIT--------------------------------------------------------------:
I managed to get the value with this code:
public void retrieveUser(final String email){
firebaseUsersRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot messageSnapshot: dataSnapshot.getChildren()) {
if(messageSnapshot.getKey().equals(Email.encodeID(email))){
retrievedUser = messageSnapshot.getValue(User.class);
break;
}
}
}
#Override
public void onCancelled(FirebaseError firebaseError) { }
});
}
Please not retrievedUser is a class attribute, thus a field. I am accessing that field from the code, but even I see it takes the value on the debugger, it is being null on the calling code.
Any hint? CanĀ“t I just return it in the method itself, so it would be?:
public User retrieveUser(final String email);
Thanks

so here is the soultion, I didn't put it in a method though.
final String uid = "your Uid here";
// Get a reference to users
Firebase ref = new Firebase(Constants.FIREBASE_URL_USERS);
// Attach an listener to read our users
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot user: snapshot.getChildren()) {
//this is all you need to get a specific user by Uid
if (user.getKey().equals(uid)){
wantedUser = user.getValue(User.class);
}
//**********************************************
}
Log.i(TAG, "onDataChange: " + wantedUser.getName());
}
#Override
public void onCancelled(FirebaseError firebaseError) {
System.out.println("The read failed: " + firebaseError.getMessage());
}
});

Related

How to retrive this data from firebase?

how can i retrieve all hospitalNames from Hospitals where all userIds are unknown.
There are two main ways to navigate the DataSnapshot that you get in onDataChange.
If you know the name of a child node in a snapshot, you can use snapshot.child("hospitalData") to get that child snapshot from its parent.
If you don't know the name of the children in a snapshot, you can loop over snapshot.getChildren() to access each child snapshot.
By combining these, you can navigate any structure.
So you'll want to loop over the users with getChildren(), then access child("hospitalData") of each user, and get the values of each individual property with something like child("hospitalName").getValue(String.class).
How about this.
final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("medicine/Hospitals");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
hospitalArrayList.clear();
for (DataSnapshot item : dataSnapshot.getChildren()) {
Hospital hospital = item.getValue(Hospital.class);
hospitalArrayList.add(hospital);
System.out.println(hospital);
}
dataRetrieved();
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("The read failed: " + databaseError.getCode());
}
});
private void dataRetrieved() {
adapter.notifyDataSetChanged();
}
Hospital.java simple example
public class Hospital {
public HospitalData hospitalData;
public Hospital(HospitalData hospitalData) { }
public Hospital() { }
public static class HospitalData {
public String hospitalName;
public String hospitalAddress;
public HospitalData(String hospitalName, String hospitalAddress) { }
public HospitalData() { }
}
}
You can use this in adapter like this.
String name = hospitalArrayList.get(position).hospitalData.hospitalName;
You have to modify your structure.
Make a new Node name hospital and put userId in each hospital object
i.e
- medicine
..........
- medicineData
..........
- Patients
..........
- Pharmacies
..........
- hospitals
..........

Can't read Firebase database, data returns null

I'm trying to get a specific user from the database but I can't, also I would like to check if there is already a node with the same name (uid). I don't want to get the whole list of users and then retrieve one from it because I don't think that's good for perfomance, my idea is to directly get the user from the database
I tried many ways but everything I try returns null, I can't get the values from dataSnapshot. I use an interface to make sure I execute the code after the reading is done
currentUser = FirebaseAuth.getInstance().getCurrentUser();
mUserReference = FirebaseDatabase.getInstance().getReference("users/"+currentUser.getUid());
mUserReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
user = dataSnapshot.getValue(User.class);
dataStatus.dataIsLoaded(user);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
Here the interface
public interface DataStatus{
void dataIsLoaded(User user);
}
And when I try to get the user it shows NullPointerException
UserUtils userUtils = new UserUtils();
userUtils.getUser(new UserUtils.DataStatus() {
#Override
public void dataIsLoaded(User user) {
mUser = user;
}
});
User creation, when I call this method I do uid = currentUser.getUid()
public void createNewUser(String uid, String name, String email, DataStatus dataStatus) {
mUserReference = mDatabase.child("users").child(uid);
mUserReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
user = new User(name, email);
mDatabase.child("users").child(uid).setValue(user);
dataStatus.dataIsLoaded(user);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
Here the rules
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
Here's how my data base is organized
SOLVED
The problem was a piece of code, which I didn't include here, that was trying to get access to the user outside the dataIsLoaded interface method, and as onDataChange is asynchronous the user hadn't been downloaded yet so it was conflicting with the code.
Welcome to SO community
Please use .child() method instead of cascading nodes with "/" as below
Also check if the value of the datasnapshot is not null using .exists() method
currentUser = FirebaseAuth.getInstance().getCurrentUser();
mUserReference = FirebaseDatabase.getInstance().getReference.child("users").child(currentUser.getUid());
mUserReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()) {
user = dataSnapshot.getValue(User.class);
dataStatus.dataIsLoaded(user);
}
}
// rest of code
Feel free if you need further support
UPDATE
Please replace your listener with below
currentUser = FirebaseAuth.getInstance().getCurrentUser();
mUserReference = FirebaseDatabase.getInstance().getReference.child("users").child(currentUser.getUid());
Query query = FirebaseDatabase.getInstance().getReference.child("users").orderByKey()
.equalTo(currentUser.getUid());
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()) { // dataSnapshot contains set of returned result of the query
User user = singleSnapshot.getValue(User.class);
if (user != null) {
dataStatus.dataIsLoaded(user);
}
}
}
}
Welcome to SO community.
When did you call your function to read the user content?
it might be an asynchronous problem.
To make sure, make a function where the user is the parameter and call it once you read something from the DB (onDataChange).
Plus, did you try to print out what is inside " user " when you read it? if it gives you null, the problem is within the path for sure. If so, use .child("users").child(currentUser.getUid())

How to link each user to their data in Firebase?

I'm trying to set up an order placing system.
Once the user is verified via email, it can create/update/delete order.
Order is saved into Firebase Real-time Database and users are saved in Authentication.
I would like to allow user to only see/edit orders that were placed by this specific user. Basically make use of UserUID from Authentication section.
public class FirebaseDatabaseHelper {
private FirebaseDatabase mDatabase;
private DatabaseReference mReferenceOrders;
private List<Order> orders = new ArrayList<>();
public interface DataStatus{
void DataIsLoaded(List<Order> orders, List<String> keys);
void DataIsInserted();
void DataIsUpdated();
void DataIsDeleted();
}
//Initialize Database object
public FirebaseDatabaseHelper() {
mDatabase = FirebaseDatabase.getInstance();
mReferenceOrders = ((FirebaseDatabase) mDatabase).getReference("order");
}
public void readOrders(final DataStatus dataStatus){
mReferenceOrders.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
orders.clear();
List<String> keys = new ArrayList<>();
for(DataSnapshot keyNode : dataSnapshot.getChildren()) {
keys.add(keyNode.getKey());
Order order = keyNode.getValue(Order.class);
orders.add(order);
}
dataStatus.DataIsLoaded(orders,keys);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
public void addOrder(Order order, final DataStatus dataStatus) {
String key = mReferenceOrders.push().getKey();
mReferenceOrders.child(key).setValue(order).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
dataStatus.DataIsInserted();
}
});
}
// Update and Delete methods
public void updateOrder(String key, Order order, final DataStatus dataStatus){
mReferenceOrders.child(key).setValue(order).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
dataStatus.DataIsUpdated();
}
});
}
public void deleteOrder(String key, final DataStatus dataStatus){
mReferenceOrders.child(key).setValue(null).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
dataStatus.DataIsDeleted();
}
});
}
}
Here's what I was thinking:
When a user creates a new order then a UserUID is added to a database and nested inside 'order' so now each order can be assigned to a user that created it.
Now the next step would be to display this order to a user that created it but only if cust_id (in order) matches UserUID of a logged in user. Would that be a good approach?
Yes, it is a good approach, now you need to add to your Firebase Realtime Database now branch with your users data based on userUID, like this:
Thanks to this you will be able to connect your users with their orders data and besides you can save here more specific user data like "how many orders user create", "how many orders are active" etc.
I have added a user_id to an 'order' in the Firebase database so each order can be assigned to its user.
I got the parameter for user_id by fetching a UserUID from an Authentication section of Firebase when a new user is logged/signed in.
Screenshot of UserUID in Authentication section of Firebase
I got this value in my code by adding the following:
private FirebaseAuth mAuth;
order.setUser_id(mAuth.getCurrentUser().getUid());
Once I got the user_id assigned to each order I've created a following if statement which is implemented in my readOrders function which you can see in my original post above:
public void readOrders(final DataStatus dataStatus){
mReferenceOrders.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
orders.clear();
List<String> keys = new ArrayList<>();
for(DataSnapshot keyNode : dataSnapshot.getChildren()) {
keys.add(keyNode.getKey());
Order order = keyNode.getValue(Order.class);
**if (order.getUser_id().equals(mAuth.getUid())) {
Log.d("FirebaseDatabaseHelper", "match");
orders.add(order);
}else {
Log.d("FirebaseDatabaseHelper", "error");
}**
}
dataStatus.DataIsLoaded(orders,keys);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
So basically now when the new user logs in, there will be nothing to show because the user_id won't match with any of the user_id's inside Order database.
I'm not sure how efficient this method will be when more users/orders will be added so I'll have to do some testing.
Please advise if this is the best approach!

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) {
}
});

Categories

Resources