2

I'm very new to Cloud Firestore, so please help me. I'm creating an app for teensagers where I want to display a list of very nice locations in every city. I also want that every user can save any location to a favorite section so he or she can show that location list to his or her friends.

My actual data:

  • db -> users (all users)
  • db -> locations (all locations)

My problem:

I want to find a way to set a location for a user as favorite. I'm thinking to create a new section under each user to hold every favorite location like:

  • db -> users (all users) -> favorite

My question:

How to make the connection between one user and favorite location/locations? I think it is a one (user) to many relationship. What is the best solution to do this?

Any idea or piece of code will be appreciated!

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
Oleg Caralanski
  • 330
  • 2
  • 10

1 Answers1

2

What is the best solution to do this?

I know that everyone is looking for the best solution but in the land of NoSQL databases, there is no best solution. There are many ways in which you can model a database for an app like yours and have the same result and and I'll demonstare you why. Before that, please take a look at my answer from this post, to have a better understanding about the concept of "perfect", "the best" or "the correct" solution in case of a NoSQL database.

The best solution is, just kidding :) A recommend way in which you can achieve this favorite feature list that you are look for, is to use arrays. Your database schema might look like this:

Firestore-root
   |
   --- users (Collection)
   |     |
   |     --- uid (document)
   |           |
   |           --- favoriteLocations: ["favoriteLocationId", "favoriteLocationId"]
   |
   --- locations (Collection)
         |
         --- locationId (document)
               |
               --- //Location details

As you can see, the favoriteLocations array holds only location ids. So in order to get location details, you should get those ids and make an extra database get() call.

Another approach would be, instead of storing an array of location ids, to store an array of maps or an array of location objects. This option works fine if you have a reasonable number of favorite locations, let's say 5, 10 or even 50 but not 500. If you'll need to store 500 location, what is the reason you'll store a location as favorite?

An important thing to remember in this case, is that the documents have limits. So there are some limits when it comes to how much data you can put into a document. According to the official documentation regarding usage and limits:

Maximum size for a document: 1 MiB (1,048,576 bytes)

As you can see, you are limited to 1 MiB total of data in a single document. When we are talking about storing text, you can store pretty much but as your array getts bigger, be careful about this limitation.

If you want to store more data that a single documents allow you to store, then you should use collections. This way you can create a subcollection under each user object that will hold as documents, location objects. Your database structure should like something like this:

Firestore-root
   |
   --- users (Collection)
   |     |
   |     --- uid (document)
   |           |
   |           --- favoriteLocations (Collection)
   |                |
   |                --- favoriteLocationId (document)
   |                       |
   |                       --- //Location details
   |
   --- locations (Collection)
         |
         --- locationId (document)
               |
               --- //Location details

To query a database that looks like this, please use the following lines of code:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference favoriteLocationsRef = rootRef.collection("users").document(uid).collection(favoriteLocations);
favoriteLocationsRef.get(/* ... */);

Another approach would be to denomalize your data and create your favoriteLocations subcollection, as a top-level collection like this:

Firestore-root
   |
   --- users (Collection)
   |     |
   |     --- uid (document)
   |           |
   |           --- //User details
   |
   --- locations (Collection)
   |     |
   |     --- locationId (document)
   |           |
   |           --- //Location details
   |
   --- favoriteLocations (Collection)
         |
         --- uid (document)
              |
              --- userFavoriteLocations (collection)
                    |
                    --- favoriteLocationId (document)
                           |
                           --- //Location details

The corresponding query should look like this:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference favoriteLocationsRef = rootRef.collection("favoriteLocations").document(uid).collection(userFavoriteLocations);
favoriteLocationsRef.get(/* ... */);

Or an even easier way, would be like this:

Firestore-root
   |
   --- users (Collection)
   |     |
   |     --- uid (document)
   |           |
   |           --- //User details
   |
   --- locations (Collection)
   |     |
   |     --- locationId (document)
   |           |
   |           --- //Location details
   |
   --- favoriteLocations (Collection)
         |
         --- locationId (document)
               |
               --- uid: "uid"
               |
               --- //Other location details

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
Query query = rootRef.collection("favoriteLocations").whereEqualTo("uid", uid);
favoriteLocationsRef.get(/* ... */);

As you can see, I have added the uid of the user as a property of the location object so you can simply get all favorite locations a particular user has.

It's up to you to choose which solution is "best" for your app use-case :)

P.S. Please also take a look at my answer from this post where I have explained more about collections, maps and arrays in Firestore.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193