Need advice for datastructure

I am making a phoenix app with quizes etc. and would appreciate some advice on how to model the data. Initially I thought a list would suffice for the anwers but quickly realised that I won’t be able to store which of the answers are correct. I starded thinking and came up with couple of roadblocks/questions. The structures I thought could be used

  • map with a nested list
correct: [answer1, answer2], 
incorrect: [answer3, answer4] 
  • keyword list with lists
correct: [ answer1, answer2 ],
incorrect: [ answer83, answer4 ]

Since there is nothing else related to the answer, eg, points, I disregarded keyword list with nested maps.

What would be the best practice in such case and how am I going to represent it in postgres ?

Any help appreciated.

  1. Is ordering of the keys important? - If no, then map, if yes, then keyword list.
  2. Can keys be duplicated within single instance? - If yes, then keyword list, if not, then map.

Remember that keyword lists have linear key lookup while maps have logarithmic key lookup.

1 Like

Order is not important and I wouldn’t really worry about the access time as for one question there will be max 6 answers but multiple can be correct though.

Isn’t easier to store them in 2 lists instead?

defmodule Quiz do
  use Ecto.Schema

  schema "quizes" do
    field :question, :string
    field :correct_answers, {:array, :string}
    field :wrong_answers, {:array, :string}

Alternatively you can consider using embed:

defmodule Quiz do
  use Ecto.Schema

  schema "quizes" do
    field :question, :string

    embeds_many :answers do
      field :correct, :boolean
      field :label, :string

Two lists have the downside of making it more tricky to order answers independent of if they’re correct or incorrect ones. I’d probably go with a list of maps.

For my first example you can always use Enum.shuffle/1 and in the second example we can add position field of type integer, so the order can be set by user creating specific quiz.

Two lists are faster to check if answer is correct answer in quiz.correct_answers (i.e. no need to loop all answers including wrong). However the embed scenario is more flexible (like above we can easily add custom positions).

Interesting, didn’t think of that. The order isn’t important so the shuffle will work for me. Added bonus would be different position for the correct answers for the same question every time. I quite like it.

I’d just use one list. Correct or not shall be computed on the fly; I don’t see the point to store this info.

Or were you trying to model a multiple choice, multiple-answer question? Your answer83 thrown me off. In that case, I’d still use one list of tuples:

[{answer1, true}, {answer2, true}, {answer3, false}, {answer4, false}] 

answer83 was a typo. And yes, there can be multiple correct answers.
How would you describe it in your schema and what postgres field type would you opt in for?

If you really want to preserve the data structure in postgres, then you can use:

%{text: answer1, correct: true},
%{text: answer2, correct: true},
%{text: answer3, correct: false},
%{text: answer4, correct: false}

A lot of good input and food for thoughts.

@derek-zhou I like the list of maps as it would be easier in my inexperienced mind to mark the answers correct with a checkbox rather than separating them into two lists. It may also come in handy if I decided to id the answers.

I guess im gonna try both and see which one’s easier to live with. Will come back and resolve this when I’ve decided. All the help is much appreciated.

This is why I have suggested an alternative solution. :wink:

Once fetched from database the embeds_many field returns a list of maps. Also embedded data have their own ids by default, so the ecto knows if said answer is newly added or just updated. Of course nothing stops you from shuffling embedded list. :smiling_imp:

I appreciate it. Ecto is a whole new animal to me which I do not have full grasp on hence I was leaning towards staying off the embedded schema and anything I deem black magic at this point :slight_smile: I read a little bit but need to dive deeper to fully comprehend and feel comfortable and confident with it.