4
votes

When the user checks his friends list in my app, I want the app to go through each user in the list and retrieve his up to date information from the Cloud Firestore.

This is my current code:

 final CollectionReference usersRef= FirebaseFirestore.getInstance().collection("users");

            usersRef.document(loggedEmail).collection("friends_list").get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                @Override
                public void onSuccess(QuerySnapshot documentSnapshots) {
                    if (!documentSnapshots.isEmpty()){


                        for (DocumentSnapshot friendDocument: documentSnapshots) {

                            usersRef.document(friendDocument.getString("email")).get().addOnSuccessListener
                                    (new OnSuccessListener<DocumentSnapshot>() {
                                @Override
                                public void onSuccess(DocumentSnapshot documentSnapshot) {
                                    User friend=documentSnapshot.toObject(User.class);
                                friendsList_UserList.add(friend);

                                }
                            });

                        }


                        ///...

                    }

                    else
                        noFriendsFound();

                }

And this is an illustration of my wanted process:

enter image description here

As you can see, I can get the information of each user in this way, but I can't find a way to listen to this process, and proceed when I have the information about all the friends in the user's list.

Is the a way which I'll be able to get all of the friends information at once?

1

1 Answers

2
votes

Firestore does not directly support joins like you're asking for.

You could construct a chained listener using the getDocumentChanges in the QuerySnapshot to keep track of which friends you should listen to.

Imagine if you kept a map of friend listener registrations like this

Map<String, ListenerRegistration> friendListeners = new HashMap<>();

Then you could register something like this:

usersRef.document(loggedEmail).collection("friends_list")
    .addSnapshotListener(new EventListener<QuerySnapshot>() {
      @Override
      public void onEvent(QuerySnapshot snapshot, FirebaseFirestoreException error) {
        for (DocumentChange change : snapshot.getDocumentChanges()) {
          DocumentSnapshot friend = change.getDocument();
          String friendId = friend.getId();
          ListenerRegistration registration;
          switch (change.getType()) {
            case ADDED:
            case MODIFIED:
              if (!friendListeners.containsKey(friendId)) {
                registration = usersRef.document(friendId).addSnapshotListener(null);
                friendListeners.put(friendId, registration);
              }
              break;

            case REMOVED:
              registration = friendListeners.get(friendId);
              if (registration != null) {
                registration.remove();
                friendListeners.remove(friendId);
              }
              break;
          }
        }
      }
    });

Note, however that this may not actually be a good idea. You may be better off pushing enough information down into the friends_list documents that you only need to load the actual friend user document once you're actually drilling down into that friend's details.