enlightenedOne
enlightenedOne

Reputation: 171

Firestore - What is best data structure for my scenario?

I am struggling with an optimal schema for my app. Should I go with top level collections, sub-collections, arrays, etc.

Setup:

  1. My app will have many quizzes that users will participate in.
  2. Each quiz will have multiple questions.
  3. Each question will have multiple answers, only one can be chosen.
  4. Each user will answer each quiz only once.

Requirements:

  1. I need to store responses for each user and be able to report at user level.
  2. I need to see aggregate results for each quiz, for each question, number of answers.

Any help is appreciated.

Upvotes: 2

Views: 691

Answers (1)

Thingamajig
Thingamajig

Reputation: 4465

I think start with the basics, and hopefully there's cohesion throughout. Each following part seems to work on its own, you may find that together it makes sense to keep some things within documents rather than their own collection, or to maintain sub-collections rather than root collections, etc.:

  • Each quiz can have its own document in a collection quizzes.
  • Each question (with its potential answers) can have its own document in a collection question.
  • Each answer to a question can have its own document in a collection answers to avoid storing the answer with the question.
  • Each user, in users
  • Each user's answers, in users/quizzes

You can consider nesting the questions within quizzes, but you may wish to keep them root level so you can easily reuse questions for multiple quizzes.

So may be worth keeping an array in each question's document for which quizzes that question belongs to.

You can then perform a query like this to get all questions for a quiz:

db.collection('questions').where('quizzes','array-contains', quizId)

That would get you all questions for each quiz and satisfy your 2nd req (and 1st is already satisfied).

The questions would come with their potential answers, which I think should each be given their own id. Like this:

-- question1
----- "Do you xyz?"
----- potentialAnswers
--------- { id: xyz123, answer: "Yes" }
--------- { id: wxy456, answer: "No" }

What this allows you to do is take each answer a user gives, and query to see if that exists as a match in your answers database.

I like this so far because it allows you to query for all questions and you get all potential answers in one query/one organized list. You can rearrange the potential answers when you display them, so "C" in each display of multiple choice does not need to always be the same "C." As long as the ID is a match when you go to compare, you're solid.

That comparison may look like this:

db.collection('answers').where('questionId','==', 'question1').where('answerId', '==', 'xyz123')

If you get a doc returned with a query like this, they've answered correctly.

For every answer a user gives, I would mark it in a sub-collection of each user, where the quizId is the ID of the document. So under user1, they'll have a collection called quizzes.

As a user answers, you can push to a map within that user's quiz document the answer they gave. This might look like this:

-- user1
----- quizzes
-------- quiz1
----------- progress: 2/25
----------- complete: true
----------- score: 1/2
----------- answers
-------------- { questionId: question1, answer: xyz123, correct: true }
-------------- { questionId: question2, answer: rst456, correct: false }

For every quiz you want the user to take, as long as no document with that quizID lives in {userID}/quizzes} with complete=true, they can start it, or continue taking it, etc.

This is more than most people get, so hope it's helpful. Some things may need to be fleshed out a bit more and others may have differing opinions, but I like these exercises.

Upvotes: 5

Related Questions