Reputation: 3557
I'm struggling with Firestore. The question is how to structure data, without running into a billing trap / nightmare.
I have following data structure:
school
course1
section1
page1
page2
section2
page1
page2
...
I assume that a course usually would not have more than 50 sections.
Use a collection
So I could use a collection and create a document for each section that contains the name and description of each section.
db.collection("schools")
.document("school1")
.collection("courses")
.document("course1")
.collection("sections").snapshots()
Document Structure:
name: "Section 1"
description: "Description 1"
However if I need to display a list of the sections, then according to Firestore billing, I would get charged for each read of a document. Which means if there are 20 sections, I would get charged for 20 reads.
Use a document with nested collections
I could also just create a document "Course 1" and nest all the sections.
db.collection("schools")
.document("school1")
.collection("courses")
.document("course1")
.get()
Document Structure:
name: "Course 1"
description: "The description",
sections: [
{
name: "Section 1",
description: "Description 1"
pages: [
{name: "Page 1", description: "Page Description 1"},
{name: "Page 2", description: "Page Description 2"}
]
},
{
name: "Section 2",
description: "Description 2"},
pages: [
{name: "Page 1", description: "Page Description 1"},
{name: "Page 2", description: "Page Description 2"}
]
...
]
Then I would only get charged for 1 read. Most likely I would not run into the 40'000 attributes limit and also not into the 1 MB limit.
But it looks like it takes some time to load the data from the document using FutureBuilder, which seems to be faster, if I get the documents in the collection with StreamBuilder.
So I somehow can't decide, which approach to take. It would somehow be more logical to use a collection because I will never run in any limits, and it seems faster to load, but from a billing point of view, it would make more sense, to nest the sections.
What option is the better one?
Upvotes: 4
Views: 3227
Reputation: 576
I agree with you that it is difficult when to choose a sub-collection approach over the conventional multiple collections approach. So please keep in mind the following cases when you decide to choose a sub-collections approach.
When to use sub-collections:
1) When you don't want to store a lot of fields in a document. Cloud Firestore has 20,000 field limit. (If the Schools and Courses information can exceed more than 20,000 fields)
2) When updating the parent collection is a common operation. Firestore only lets you update the document at rate of 1 write/second. (If the Schools,Courses and Pages information is modified very often)
3) When you want to limit the access to particular fields of a document. (If you want to restrict the access to a Course's Pages. In this case moving the restricted fields to another document in another collection is also a good idea!)
When not to use sub-collections:
1) When you want to query the collections and sub-collections together. Firestore queries are shallow. So sub-collections won't be queried when you query the parent collection so you have to query them separately. (If you have a case to show all the schools and their courses in one window)
2) When you want to show the sub-collection when viewing the collection.(When showing a school, you might want to show its courses. Here the number of reads will increase because instead of reading one document you are reading one document and its sub-collection all the time)
3) When you want to query collections and sub-collections together.(You have to use collection group query as sub-collections are essentially collections.)
4) If you're thinking about querying individual pieces of data, you should put them in a collection. (If the School's particular attributes are usually queried by users or a Course's details are looked upon by multiple users)
My Suggestion:
Schools
- Array<CourseIds>
- Other info
Schools
collection to store school information on which schools can be searched according to their qualities. Schools information can also contain a field courses_available which can be an array or map to store the course name alone and its unique id
.
Courses
-Course info
Courses
collection with the same approach since I'm assuming course information will be queried a lot according to their attributes.
CourseSections
-Course1Section1
-Pages
-Course1Section2
-Pages
CourseSections
collection for info about the course sections which has a sub-collection
Pages
.
Advantages:
CourseSection
can be read on demand, so that you don't need to read all of its sections while reading a Course
. Ultimately the choices depends on the use cases you have.
Hope this helps.
Upvotes: 3