Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cloud Firestore schema with sub collections

Tags:

I'm switching from Firebase Realtime database to Cloud Firestore. My database contains Users that owns Storages, each Storage contains Boxes. Each User can own several Storages that contains Boxes. Each Storage can contain several Boxes. Each Box can only be in one Storage.

In the main view in my app, for that specific user, I would need to list all Storages with the Boxes in each Storage, like this:

Storage 1:
    Box 1
    Box 2
Storage 2:
    Box 3
    Box 4
    Box 5
...

The user should then be able to tap into each Box to see the content and more information.

In the Firebase Realtime database this was possible to get with one request per user. Now with Firestore I'm not sure how to create the best model as I can only do shallow reads. I can not get the Storages with all connected Boxes to it in one request if I use sub collections. To then get all Boxes I would need to first do one request to get all Storages and then one for each Storage to get the Boxes.

My idea for a structure in Firestore would be one of the following, but I'm not sure it's the way to go:

Structure 1:

Using two separate collections

Storages Collection
    storage_1:
        name: "Storage number one"
        user_id: "1"
    storage_2:
        name: "Storage number two"
        user_id: "1"

Boxes Collection
    box_1:
        storage_id: "1"
        user_id: "1"
    box_2:
        storage_id: "1"
        user_id: "1"

The problem with this solution is how I would get the name of the Storage when loading the Boxes collection for a specific user. I would then also need to sort them in under each Storage locally.

My other idea for a structure would be:

Using two separate collections and a dictionary under the Storage Collection.

Storages Collection
    storage_1:
        name: "Storage number one"
        user_id: "1"
        boxes: [{ box_id: "1", name: "Box number 1" }, { box_id: "2", name: "Box number 2" }]
    storage_2:
        name: "Storage number two"
        user_id: "1"
        boxes: []

Boxes Collection
    box_1:
        storage_id: "1"
        user_id: "1"
    box_2:
        storage_id: "1"
        user_id: "1"

Is any of these structures a good solution considering my explained UX above or is there a better way that I've missed?

like image 403
Martin Avatar asked Nov 17 '17 12:11

Martin


1 Answers

Here's how I might structure your data.

Note that I'm putting Storage as a subcollection under your Users collection, but that's entirely optional. If each bit of storage can only be owned by one user, it might be nice to keep this as a subcollection as I've shown below. But if one storage item can be owned by multiple users or will switch users often, you're probably better off making it a top-level collection.

 + Users (collection)
     * user_a (document)
         - name: "Joe"
         - last_login: 20171130
         + Storage (subcollection)
             * storage_1 (document)
                 - name: "Living Room Storage"
                 - box_summary: {box_1: "Fancy box", box_2: "Plain box"}
                 + Boxes (subcollection)
                     * box_1 (document)
                         - name: "Fancy box"
                         - contents: "Gold coins and jewels"
                     * box_2 (document)
                         - name: "Plain box"
                         - contents: "Books"

I think the important item to note here is the box_summary entry of the storage document. This contains just enough information that you can give the users what they need on their initial "View my storage" screen without having to make a bunch of separate requests, but it comes with the drawback that you will need to do a little bit of extra work to keep that data in sync. Whether that tradeoff is worth it to you depends on how often you think your users will be adding or removing boxes, and how often they'll be viewing this "View my storage" screen.

like image 78
Todd Kerpelman Avatar answered Sep 22 '22 13:09

Todd Kerpelman