Firebase/Firestore Experts.
So I have got a question about structure, as I have now run into a problem, and it got me thinking if I actually have the right structure.
I’ll try to explain…
I have an application where it is possible for companies to create a profile. Each company has a companyId. Each company can create courses, which means I have a collection named "Courses". This collection looks like this:
CourseCollection
- Doc (CompanyID)
- Subcollection (Categories)
- Subcollection (Courses)
- Doc (CompanyID)
- Subcollection (Categories)
- Subcollection (Courses)
The reasoning for structuring like this was so it was easy to have a collection that had the specific companies and the company’s own categories and courses. I thought that might be a smarter solution than having a flat collection of all courses ever created and having a companyId as a property on the course. I don’t know if this solution is better or if it is better to have a flat structure.
Just to mention, a course document holds an "events" array, where each "event" has a start date.
Anyway, now I want to set up a function to run daily. The function I am setting up needs to run through all courses for all companies and see if it has any active events for "today" and then send out an email to a user that is signed up for the course. However, then I found myself not being able to query the "Courses" collection – The following returns me nothing
export const dailyCourses = async () => {
const coursesByCompanies = query(collection(db, 'courses'));
const checkCourseForNewClientProgramSnapshot = await getDocs(coursesByCompanies);
checkCourseForNewClientProgramSnapshot.forEach((courseSnapshot) => {
console.log('courseSnapshot', courseSnapshot.data());
});
};
However, if I specify a companyId and the subcollection, I can get all the courses for the given companyId
export const dailyCourses = async () => {
const coursesByCompanies = query(collection(db, 'courses/**someId**/courses'));
const checkCourseForNewClientProgramSnapshot = await getDocs(coursesByCompanies);
checkCourseForNewClientProgramSnapshot.forEach((courseSnapshot) => {
console.log('courseSnapshot', courseSnapshot.data());
});
};
Now, that got me thinking that it might not be possible to loop over all root documents in the courses collection and get all the "courses" (subcollection) for each company, without me knowing each companyId beforehand to look up each course in the subcollection?? Which means I could have to query all companies in my "companies" collection before and get all ids of the companies which might not be the best, as all companies may haven’t created any courses, which would cause me to do a lot of unnecessary reads?
So now I’m thinking that I might be better off actually having a flat structure, after all, containing all courses and then querying them by companyId. Then I can loop all courses and the events and see which events match the current day (today).
As you might hear, I’m a bit confused about which is the best solution, which is why I’m looking for any expert advice. I’m thinking I’m not the first to have run into an issue like this or similar before.=
I know a lot of you would say "Read the docs" or "It depends on the use case", etc – I have read the docs, however, this doesn’t say anything about which solution I would/should use in THIS specific case, so I’m REALLY hoping that someone could give me their thoughts and perspectives. It should also be said I’m still quite new to Firebase/Firebase, so if you can see that there is an even better solution for it than I have proposed, I’m all ears 🙂
THANK YOU for your time in advance 🙂 I’m really hoping a helpful soul is coming my way 😉
2
Answers
For simplicity I’d prefer having a separate collection for courses with a reference to the company it belongs to.
Not only would it reduce reads, but it makes your code a little easier to write and maintain. Plus if there are some option in the future to have public courses etc.
Not really sure if there is more I can add to it, but it’s as simple as the above if I was to do it.
We are usually structuring a Firestore database according to the queries that we want to perform. So the following answer will most likely help.
The shared structure looks good to me.
None of the solutions is better than the other. If any structure allows you to query and get the correct results, then that’s the one you should go ahead with.
That can be achieved in a very simple way, by using a collection group query, which will allow you to get the desired data from all sub-collections called for example, "courses".
Besides that, your first code snippet doesn’t work because there is no top-level collection called "courses". The second snippet works because you are pointing exactly to the courses of a particular company.
No need for that.
There is no best solution. However, your schema can solve the queries that you were talking about.