1

I am designing a social app using java android with FireStore as backend. In the beginning, Firestore modeling can be a big change, as I have read I am trying to keep Documents small and not to make too many subcollections, let´s suppose the following scenario:

A User can create a few profiles
A profile has interests
A user can follow or unfollow many profiles so a profile can be followed by a lot of users

Users (Collection)

uid: uidUserOne
name: jeff

Profile (Collection)

idProfile: idProfileOne
name: nameProfileOne
interests: { yoga: true, running: true, climbing: true }
createdBy: uidUserOne

Here start my doubts not sure how to model de Follow/unfollow functionality, I have three options in mind:

Option A

Make a collection in which each document maps a single user follows one profile relationship

followers (Collection)

uid: uidUserOne
idProfile: idProfileOne

Option B

One document maps the followers of each profile, I save the user UIDs that follow the profile in an array.

followers (Collection)

idProfile: idProfileOne
followers: { uidUserOne: true, uidUserTwo: true, ...}

Option C

One document maps the follows of each user, I save the profiles ids that are followed by the user in an array

followers (Collection)

uid: uidUserOne
follows: { idProfileOne: true, idProfileTwo: true, ...}

I would like to know which options are the best, A B r C also if it can be a better one... probably

And I have another doubt, how can I do the following query:
Let's say I am user One and I already follow two profiles with yoga interest so I want to list, profiles with yoga interest which I do not follow yet, not sure how to accomplish this.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
Juan
  • 229
  • 2
  • 6
  • 20

1 Answers1

1

As far as I can see, your answer provides a solution to the following system that is related to the Realtime Database, while your question is related to Firestore. Please note that both databases are a part of Firebase but both are two different products, with two different mechanisms.

And to answer your questions:

Option A. Make a collection in which each document maps a single user that follows one profile relationship

Even if this solution sounds a little costly, since everything in Firestore is related to the number of reads, might be a solution to take into consideration for an app with a reasonable number of users/followers. I have answered a few years ago a similar question, so please check my answer below:

However, imagine the cost of reading a user who has 1 MILLION followers?

Option B. One document maps the followers of each profile, I save the user's UIDs that follow the profile in an array.

That's also a solution to go ahead with. But also remember that the documents have limits, so I'm afraid that 1 MILLION UIDs doesn't fit into a single document. However, you can create a new document every time you reach the limitation. I have created a library that can help you check the document size against the 1 MiB maximum size:

Option C. One document maps the follows of each user, I save the profiles ids that are followed by the user in an array

This option is the same as option B.

Let's say I am user One and I already follow two profiles with yoga interest so I want to list, profiles with yoga interest which I do not follow yet, not sure how to accomplish this.

In this case, the "collection" solution is the one to go ahead with because you can add an array of interests to each UID document that follows a user.

Edit:

Let's assume you are interested in following users who have interests in yoga that you don't follow. Here is a schema that can help you achieve that:

Firestore-root
  |
  --- users (collection)
  |    |
  |    --- $uid (document)
  |         |
  |         --- interests: ["yoga", "running", "climbing"]
  |
  --- followers
       |
       --- $uid (document)
            |
            --- userFollowers (sub-collection)
                  |
                  --- $followerUid (document)
                        |
                        --- //Data

To get the desired results, you need two queries. One to get the users that are interested in yoga, and the second one, to get only the one that you don't follow. Actually, you need to check which user is not present in the userFollowers sub-collection. To check if a user doesn't exist, please use the following lines of code:

String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
DocumentReference followerUidRef = rootRef
    .collection("followers").document(uid)
    .collection("userFollowers").document(followerUid);
followerUidRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
    @Override
    public void onComplete(@NonNull Task<DocumentSnapshot> task) {
        if (task.isSuccessful()) {
            DocumentSnapshot document = task.getResult();
            if (!document.exists()) {
                //Follow the user
            }
        } else {
            Log.d(TAG, "get failed with ", task.getException());
        }
    }
});
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Hi Alex!! Thanl u very much for your answer , and yes It has been quite useful, I didn´t know about the "create new document o contnue increasing...", but still can figure out how to implement the last query could you explain a bit further your solution?? one example of data modelling wouls be great!! – Juan Aug 13 '21 at 12:21
  • You can simply create a new document, at the moment you reach its limits. Basically, the document will be only a container for holding data. As soon as it gets to 1Min, simply create another, and so on. But don't forget to always check the size, otherwise, the query will see operation fail. Regarding the query, add an array of interest in each object and use whereArrayContains method. – Alex Mamo Aug 13 '21 at 12:36
  • "Regarding the query, add an array of interest in each object and use whereArrayContains method" Alex still not undestanding your solution which document you mean? can you prvide example ? – Juan Aug 13 '21 at 12:49
  • I'll try to edit my answer when I get back to my computer. – Alex Mamo Aug 13 '21 at 13:11
  • Sorry for my late edit. Please check my updated answer. – Alex Mamo Aug 14 '21 at 07:28