One of the downsides of the Firebase Realtime Database is its inflexibility with data structuring. If you want to perform queries that look at different data nodes you almost always need to denormalize your data. This has the benefit of
- Decomposing your data into discreet chunks
- Better querying for stats etc
- You don't have to download massive chunks of nested data
The downside is that:
- Your data requires multiple combined queries e.g
user-by-username' or
groups-by-user`.
- It seems a bit convoluted and non-intuitive
Back to your question:
Given the following table structure:
group
group1
name:"Best group"
description: "The best group"
group2:
name:"An okay group"
description: "A decent group"
user
user1
name: "User1"
user2
name: "User2"
group-by-user
user1
group1: true
group2: true
user2
group2: true
Note how I have created a new table that will associate a user to a group without having to place this info in the user table. This ensures that the user table is solely for base non-relational user information.
To query this in Java, it would look something like the following
//Get a reference to groups a user is in
//get a reference
DatabaseReference groupByUserRef = FirebaseDatabase.getInstance().getReference();
//get a reference to the join table mentioned above
groupByUserRef.child("group-by-user").child("user1").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//This contains a list of group keys associated to the user;
Iterable<DataSnapshot> groupsByUser = dataSnapshot.getChildren();
//iterate through the list of group keys associated to the user
groupsByUser.forEach(groupDatasnapshot -> {
String groupId = groupDatasnapshot.getKey();
FirebaseDatabase groupReference;
DatabaseReference groupRef = FirebaseDatabase.getInstance().getReference();
//Once the key has been retrieved, do a search in the database to get the group
groupRef.child("group").child(groupId).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Here is where you will get the groups associated to the user.
Group group = dataSnapshot.getValue(Group.class);
//Add logic here ..
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
});
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
EDIT
To conclude
As mentioned above you can see it is a very convoluted approach.
This is a drawback of the Realtime database. If you would like to ensure not looping over keys you have the following option.
- Don't denormalize your data and have the group information directly within the
user table. This has the downside of you having to pull large sets of data when your group info grows (some of which you wont need).
- Use firebase cloud firestore - they have managed to solve the problem here