I'm building a fullstack todo app using firebase to store user information. My idea is that each user can create multiple lists and write multiple 'todos' in every list (eg. Have a list for today and another for tomorrow). My data is structured in this manner:
users (collection) -> usersID (every user is a document) -> todos Lists (collection) -> todoId (document) -> (object with the data)
I can't seem to be able to query the multiple lists a user might have (by default, I'm currently just retriving data from the 'todos' collection). Either I'm failing to see some firestore functionality or I'm not structuring my database correctly. Any advice?
CodePudding user response:
You are structuring your data fine. The problem is that the Firebase Client SDK
doesn't offer a function to retrieve all subcollections a document has. To solve your problem you got multiple options.
1. The cleanest but most exhaustive way
You upgrade to the Blaze Plan and use Firebase Functions with the Admin SDK. The Admin SDK offers a function called listCollections()
which exactly does what you want. The disadvantage is that Firebase Functions have something called coldstart
which means that when your function was idle for some minutes it takes up to 20 seconds (from my experience) to run again after you called it, which can be really frustrating. Otherwise you can run a free node.js server on something like Heroku to use the Admin SDK there to avoid coldstart (better option in my opinion). The Admin SDK is explicitly not meant to be used on the client side. Check this thread
2. List all your todo lists (easiest way)
Everytime the user creates a new list, you add that to an array in your users document like this:
// Representation of your user document
user
name: "Florian"
lists: [
"todos",
"anotherList"
]
So in that way you can just fetch your user, get the lists property from it and call all lists with a loop over the lists
array. As alternative just display the lists
content and let the user open it explicitly to save reads.
3. Restructuring your database (I would recommend it)
If you don't have a lot of data yet, I would recommend to restructure your database like:
users - the collection with all your users (without the todo list subcollections
lists - containing a document for every created list
- each document contains a field with `owner`
- each document contains a field with the list name
- each document owns a subcollection with todos
If you use this way you could just query the database like
const getLists = async () => {
const ref = collection(db, 'lists');
const q = query(ref, where('owner', '==', theUserYouWantToQuery);
// returns array with all list (including listname) of that user.
const lists = (await getDocs(q)).docs.map(doc => ({ ...doc.data(), doc.id }));
}
when you have all list objects from that user you can either loop over that array to get all todos in the lists or let the user only fetch one list by opening it