Christopher Armstrong
Christopher Armstrong

Reputation: 3557

Document vs Collection

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

Answers (1)

denniskbijo
denniskbijo

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:

  1. This will help you to add a lot of pages to each section.
  2. 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

Related Questions