CONTEXT
I am currently working on a Firebase application (in Android). I have set up authentication, storage and the database with no issues to speak of. As the Firebase auth user only has a few properties, I have created a "user" POJO to store additional user information that is not contained inside of the Firebase auth user (ie first name, date of birth, nationality, etc...). The structure of this is shown in the image below:
The UUID in the image is the users respective auth uid. This was achieved as such:
ref.child(users).child(auth.getUid()).setValue(user);
This approach seems in line with the documentation as it allows me restrict write/read to the account owner using the auth.uid === $uid
rule. Furthermore, all of the properties inside of the tree map to my POJO as expected.
PROBLEM
My one big problem is that I want to store the users uid inside the POJO. As the UID is currently structured as the objects parent, I am not sure how to map it to the user POJO. I could of course store an additional field in the bottom tree level. However, that seems like pointless data redundancy.
QUESTION
What is the best way to map the uid to a respective "user" POJO class. Ideally I'd be able to fetch 10 users to display, and when one is tapped have the app load a profile activity. This would mean passing the uid of the user, so I can say:
ref.child(users).child(targetUID)
and fetch the tapped user account. This means having their uid.
I had the same problem while using FirebaseRecyclerAdapter
, so I copied the code and added the following method since the adapter stores the snapshots.
public String getItemKey(int position) {
return mSnapshots.getItem(position).getKey();
}
Now you can just set the user's UID using a setter.
EDIT :
I was thinking something along these lines
User.java
public class User {
private String name;
private String email;
private String UID;
public User() {
}
public String getUID() {
return UID;
}
public void setUID(String UID) {
this.UID = UID;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And in your Firebase adapter's populateView()
String UID;
FirebaseListAdapter<User> searchAdapter = new FirebaseListAdapter<User>(getActivity(), User.class, R.layout.user_layout, mRef) {
@Override
protected void populateView(View v, User model, int position) {
// If you really need to set the UID here
// model.setUID = getRef(position).getKey();
// Otherwise, I would just set a String field as shown
//and pass it with the intent to get the UID
//in the profile Activity
UID = getRef(position).getKey
((TextView) v.findViewById(R.id.text1)).setText(model.getName());
((TextView) v.findViewById(R.id.text2)).setText(model.getEmail());
v.setOnClickListener(MainActivity.this);
}
};
@Override
public void onClick(View v) {
Intent intent = new Intent(this, ProfileActivity.class);
intent.putStringExtra(UID_EXTRA, UID);
startActivity(intent);
}
I used two approaches to solve this. One is to have that extra field, thus having the redundancy, and the another is to use a HashMap to map the User's POJO with it's UID.
If you have noticed that whenever you load the data from the Firebase Database, mostly it's in the form of a Map, so all I did was to save the key to a Map, which uses that key to map the User's POJO. That map was stored in a singleton so it could be accessed from anywhere in the app.
Something like this -
DatabaseReference mFirebaseRef = FirebaseDatabase.getInstance().getReference("users"); //Add your filter as your requirements. I am currently loading all the users.
mFirebaseRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Map> map = (Map<String, Map>) dataSnapshot.getValue();
if (map != null) {
for (String uid : map.keySet()) {//keys will be uid
Map<String, Map> userMap = map.get(uid); //userMap is a single user's data.
User user = new User(userMap); //I have used a constructor to map the populate the properties of the User Model.
getSingletonMap().push(uid,user); //pushing using the uid
}
}
}
This way I can get the user just by using the UID ( getSingletonMap().get(uid)
)or can get the uid of a user. I hope this answers your question.