Home > other >  How to query many to many relationship in Firebase for Android?
How to query many to many relationship in Firebase for Android?

Time:07-20

I'm trying to build a simple shopping list android app with a firebase database.

Quick context: User registers with email and should be able to create a group to share a shopping list that belongs to the group (and all the members of the group). And then later on shopping list items are added to the shopping list.

I'm a bit stuck on how to handle the many-to-many relationship between the users and the groups. I read this post: enter image description here

What I don't really understand that how I will query this exactly. As we use value event listeners in Firebase, my guess was that I would need to attach the listener to the database reference and save the related data locally in the app to populate the screens. For example, I would like a recycler view with all the groups that belong to the user, where the cards would display the name of the group, the creation date of the group, and the group members. Based on the above data structure, that's 4 separate value event listeners nested into each other, is this correct?

This is part of the code that I have written and this is only saving the userIDs for each group so it would require another nested query:

//get group ids - there is at least one as own_group is set up with the user details
Utils.userGroupReference.child(Utils.firebaseUserID).addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        for (DataSnapshot groupIDSnapshot : snapshot.getChildren()) {
            Utils.myGroupIDs.add(groupIDSnapshot.getKey());
        }

        for (int i = 0; i < Utils.myGroupIDs.size(); i  ) {
            //get groups based on group ids
            Utils.groupReference.child(Utils.myGroupIDs.get(i)).addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {
                    Group group = (snapshot.getValue(Group.class));
                    GroupUser groupUser = new GroupUser(group);
                    Utils.myGroups.add(group);
                    Utils.groupUserReference.child(snapshot.getKey()).addValueEventListener(new ValueEventListener() {
                        @Override
                        public void onDataChange(@NonNull DataSnapshot groupUserSnapshot) {
                            ArrayList<String> userIDs = new ArrayList<>();
                            for (DataSnapshot userIDSnapshot: groupUserSnapshot.getChildren()) {
                                userIDs.add(userIDSnapshot.getKey());
                            }
                            Utils.myGroupUsers.add(new GroupUser(group, userIDs));
                        }

                        @Override
                        public void onCancelled(@NonNull DatabaseError error) {

                        }
                    });
                    Utils.myGroupUsers.add(groupUser);
                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {

                }
            });

I would appreciate it if someone could shed some light on this for me.

Another question is where do we normally call the value event listeners? This snippet is from the onCreate() method in the MainScreen which eventually would contain all the shopping lists. I was thinking to put it in the splash screen but my experience is that whenever a node is updated, the application will get thrown back to the screen that contains the value event listener, so I'm not sure which is a better option

Thank you very much!

CodePudding user response:

I would typically use addListenerForSingleValueEvent listeners or getData calls for some of the inner data loading here, but it is correct that you'll need a separate call for each piece of data you load.

Since Firebase pipelines all these requests over a single connection, the data is loaded really quickly - so it's really just the code that gets a bit convoluted.

If that is something you'd like to prevent, you could consider duplicating some of the data from the User into each GroupUser and/or UserGroup entry where that user is present too. This will make the code that writes the data more complex, but simplifies the data loading.

This sort of trade-off is quite common when dealing with NoSQL databases, and is one of the reasons they can scale to so many users. To learn more about this, I recommend checking out NoSQL data modeling, Firebase for SQL developers, and Getting to know Cloud Firestore (the latter is for Cloud Firestore, but many of the lessons also apply here).

  • Related