Firebase data structure with cyclic dependency

308 views Asked by At

I'm currently discovering Firebase and trying to evaluate it for further projects. At the moment, i'm testing with a very simple "Todo list" app where lists can be shared with friends.

I've read the Doc about flattening data structure to avoid complexity and I came up with the following structure:

app : {
    users : [{ "id": "user1Id", ... }]
    lists : [{ "id": "list1Id", ... }]
    membership : [{ "list1D": [{ "user1Id": true }], ... }]
}

Now i wonder how can i load all my "lists" without getting all lists from other users.

Thanks a lot for your helps and advices.

Best regards

2

There are 2 answers

1
Frank van Puffelen On BEST ANSWER

If you want to show a list to the user of all TODO lists she has access to, I would store that list in Firebase.

Stealing from Mathew's sample data:

{
    users: {
        user1Id: {
            //other data
            lists: {
                list1Id: true,
                list5Id: true
            }
        }
    },
    lists: {
        list1Id: {
            //other data,
            memberships: {
                user1Id: true
            }
        }
    }
}

So in the above snippet, you only have to load /users/user1Id to know what lists he has access to. You don't need to do any query to determine that, so loading the "list of user1's lists" is dead-cheap. You could even store the information that you want to display for each list in the user's data too, preventing the need for a lookup.

{
    users: {
        user1Id: {
            //other data
            lists: {
                list1Id: "Groceries for BBQ",
                list5Id: "4th of July parties to go to"
            }
        }
    },
    lists: {
        list1Id: {
            title: "Groceries for BBQ",
            //other data,
            memberships: {
                user1Id: true
            }
        }
    }
}

Note that in both cases we are duplicating data. I recommend doing this in many cases, since it speeds up reading the data for a specific use-case. But of course it comes at a cost of having to write the data to multiple places when you first add it. And you'll also have to consider if/how you want to update all instances of that data when e.g. the list title changes.

Read this article for a nice introduction on the topic: https://medium.com/@collardeau/es6-promises-with-firebase-76606f36c80c or this answer for my input for that article: How to write denormalized data in Firebase

Update

I just realize that you should probably normalize this data a bit. Firebase recommends that you don't build nests, when they are not needed. In this case, you might want to see a user's profile data, and you wouldn't need her lists. Or the user just wants to see her lists, not her profile data. So a more normalized model would be:

{
    users: {
        user1Id: {
            //profile data
        }
    },
    users_lists: {
        user1Id: {
            list1Id: "Groceries for BBQ",
            list5Id: "4th of July parties to go to"
        }
    lists: {
        list1Id: {
            title: "Groceries for BBQ",
            //other data,
            memberships: {
                user1Id: true
            }
        }
    }
}

It's the exact same data as before, but now the users_lists is in a separate top-level data structure.

Of course whether this structure is better depends on the use-cases you want to cater for. If you always show the user's profile data and todo-lists in one screen, the former is slightly more efficient. But either data structure is more efficient than the one most developers think of first select * from all_todo_lists where user_id = me. :-)

1
Mathew Berg On

There are no arrays, your data should look more like this:

{
    users: {
        user1Id: {
            //other data
        }
    },
    lists: {
        list1Id: {
            //other data,
            memberships: {
                user1Id: true
            }
        }
    }
}