1

I want to make a firestore schema for a little angular app I'm trying to make. My Problem is, that I don't know what schema makes most sense. I try to get good performance and as less queries as possible. My object are as following:

  • Card
  • CardList
  • User
  • Settings

The idea is, that a User has his own settings (like language etc.). He also can create a cardlist to which he can add as many cards as he want. I wanna be able to query all cards by card list, all cardlists by user, all settings by user...

Are there any Suggestions?

Yingrjimsch
  • 122
  • 1
  • 11

1 Answers1

2

A possible database schema for your app might be:

Firestore-root
   |
   --- users (collection)
   |    |
   |    --- uid (document)
   |         |
   |         --- userName: "NameOfUser"
   |         |
   |         --- settings (map)
   |         |    |
   |         |    --- language: "en"
   |         |    |
   |         |    --- //Other settings properties
   |         |
   |         --- //Other user properties
   |
   --- cards (collection)
   |    |
   |    --- cardId (document)
   |         |
   |         --- uid: "uid"
   |         |
   |         --- //Other card properties
   |
   --- decks (collection)
        |
        --- uid (document)
             |
             --- userDecks (collection)
                    |
                    --- deckId (document)
                          |
                          --- deckName: "NameOfTheDeck"
                          |
                          --- //Other deck properties
                          |
                          --- userDeckCards (collection)
                                 |
                                 --- cardId (document)
                                       |
                                       --- uid: "uid"
                                       |
                                       --- //Other card properties

The idea is, that a User has his own settings (like language etc.). He also can create a cardlist to which he can add as many cards as he want. I wanna be able to query all cards by card list, all cardlists by user, all settings by user

Using this database schema, you can simply:

  • Get all users by attaching a listener on users collection reference:

    db.collection("users").get().then(/* ... */);
    
  • Get all settings that correspond to a specific user, using the following reference and iterate over the settings map:

    db.collection("users").doc(uid).get().then(/* ... */);
    
  • Get all cards from all users by attaching a listener on cards collection reference:

    db.collection("cards").get().then(/* ... */);
    
  • Get all cards that correspond to a specific user by using a query:

    db.collection("cards").where("uid", "==", uid).get().then(/* ... */);
    

As you can, only two top-level collections are necessary. For your particular use-case, there is also no need to denormalize data, it will scale without problems.

Edit:

According to your comments, yes, you should create another collection named decks so you can get all the decks that correspond to a specific user. For that, the following collection reference is required:

db.collection("decks").doc(uid).collection("userDecks").get().then(/* ... */);

If you want to get all the cards that correspond to a specific user deck, the following collection reference is collection reference is required:

db.collection("decks").doc(uid)
    .collection("userDecks").doc(deckId)
    .collection("userDeckCards")
    .get().then(/* ... */);

In this case you need to use denormalization. This is a common practice when it comes to Firebase. If you are new to NoQSL databases, I recommend you see this video, Denormalization is normal with the Firebase Database for a better understanding. It is for Firebase realtime database but same rules apply to Cloud Firestore.

Also, when you are duplicating data, there is one thing that need to keep in mind. In the same way you are adding data, you need to maintain it. With other words, if you want to update/detele an item, you need to do it in every place that it exists.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Hi alex thanks for responding once more :) I also need to have multiple cardlists per user. This cardlist should be something like a carddeck whit a name and other properties. Would you make a collection `decks` instead and in this deck a collection with `cards`? Or how would you solve that problem? – Yingrjimsch Jan 11 '19 at 07:40
  • You're welcome :) Yes, you're right, a new collection is needed that also contains in turn another collection of user cards. Please see my updated answer. – Alex Mamo Jan 11 '19 at 08:00
  • Thanks for your edit. Now everything is much clearer. Now I have one last question. In your structure you made a collection `decks`, in this collection there are uid's (standing for ids of user?) in there is another collection `userDecks`. Isn't it possible to remove the collection ùserDecks` and to add a property uid (the id of user) to the `deck` and then querry all decks by userId as following: `db.collection("decks", q => q.where("uid", "==", uid)) .doc(docId) .collection("userDeckCards") .get().then(/* ... */);` – Yingrjimsch Jan 11 '19 at 09:22
  • `standing for ids of user?` A: Yes, that's correct. `Isn't it possible to remove the collection ùserDecks` and to add a property uid` A: Yes it is. There is no [single or perfect database structure](https://stackoverflow.com/questions/53053768/what-is-the-correct-way-to-structure-this-kind-of-data-in-firestore/53057707). If you think that quering using `"decks", q => q.where("uid", "==", uid)` makes your job easier, then go ahead with that. – Alex Mamo Jan 11 '19 at 09:27