I'm working on a Reagent App to manage seasons for a hotel-booking-site. The data is shown in a tabular view and is currently stored in an atom holding a nested map with season-ids as keys, like so:
(def seasons (r/atom
{1
{:begin "2020-04-02"
:end "2020-04-19"
:selected false
…much more data like price per room etc}
2
{:begin "2020-04-20"
:end "2020-06-18"
:selected true
}
…}))
The main advantage of this structure is easy deleting/modifying of seasons from within my components via #(dissoc @seasons season-id)
or (update-in seasons [season-id :begin] "2020-04-21")
, which would be more cumbersome with the flatter alternative of integrating the id into the map representing a season, like so:
(def seasons
(r/atom
[{:id 1
:begin "2020-04-02"
:end "2020-04-19"
:selected false
…much more data like price per room etc}
{:id 2
:begin "2020-04-20"
:end "2020-06-18"
:selected true
}…]))
This version would lend itself much better to being mapped over, which is not very pleasant with my current data model, where I have to always recombine the id with the actual map into a binary vector and then stick the resulting seq back into
a map.
I'm more and more inclined to switch to this second model as the removal/update would be feasible by passing the entire season into a function… there would be no need for ids at all then, e.g.:
(vec (remove #(= % season) @seasons))
or, respectively:
(vec (map #(if (= % season)
(update-in % [:begin "2020-04-21"]) %) @seasons))
Since this is my first real-world Reagent app I'm a bit unsure as to which data model is actually preferable? Are there any performance considerations between both approaches? Which one would seem more sane to a seasoned Reagent developer? Is there a third way that I'm unaware of?
Many thanks for any input to this somewhat open question!
As you describe your purposes (seasons), performance is not a consideration. Three "seasons" per day is only ~1000 per year - a small number to a computer.
So, which method is easier for your code? You have discussed two use-cases which come down favoring method A in one case and method B in another. It is up to you to decide.
In method A, you have "pre-indexed" the data, so you can go directly to a thing and modify it. In method B, you have to do a mini-search to find a thing, before processing it. For a larger problem, method B eventually morphs into a DB like Postgres, Datomic, or Neo4J, etc.
For small problems that stay in memory, you could use a library:
These are probably overkill at this stage, but you may want to keep them in mind for the future.