(def dbSample {
:person [{:person/id 1 :name "dan" :surname "stone" :joindate "01.06.2022" :experience :experience/starter :loyalitylevel :loyality-level/zero-one-years :worktime :worktime/internship :managers {:manager/id 1}}
{:person/id 2 :name "dave" :surname "jhons" :joindate "04.04.2021" :experience :experience/medior :loyalitylevel :loyality-level/one-two-years :worktime :worktime/full-time :managers {:manager/id 1}}
{:person/id 3 :name "patrick" :surname "square pant" :joindate "09.01.2022" :experience :experience/senior :loyalitylevel :loyality-level/zero-one-years :worktime :worktime/part-time :managers {:manager/id 1}}
{:person/id 9 :name "rich" :surname "hickey" :joindate "04.04.2016" :experience :experience/lead :loyalitylevel :loyality-level/more-than-seven-years :worktime :worktime/part-time}
]
:employees/developerteam [{:frontend [[:person/id 1] [:person/id 2] [:person/id 3]]
}]
:employees/managers [{
:manager/id 1 :manager/person [:person/id 9]
}
]
:relations/experience {:experience/starter "0-1"
:experience/medior "1-3"
:experience/senior "3-6"
:experience/lead "6 "
}
:relations/loyalitylevel {:loyality-level/zero-one-years "0-1 year(s)"
:loyality-level/one-two-years "1-2 year(s)"
:loyality-level/three-five-years "3-5 year(s)"
:loyality-level/five-seven-years "5-7 year(s)"
:loyality-level/more-than-seven-years "7 year(s)"}
:relations/worktime {:worktime/full-time "full time"
:worktime/part-time "part time"
:worktime/internship "internship"}}
)
Hello everyone, I started to learn Clojure and to try to do some exercises to understand it better. How can I find the frontend team member's manager's name? I getting their ":person/id" with that function that you can see at the bottom. Now I wondering how can I reach their manager's names.
I just created a sample data (it is little bit more complex but I cut off extra complexity) to learn how to get data and travel inside data. I want to give input to my second function's output and I want to see who are these person managers. I don't know if it is easy or possible.
(defn getFrontendDeveloperTeamMembersIds [] :docstring "get frontend developer team members references"
(->> dbSample
(:employees/developerteam)
(first)
(:frontend)
)
)
(getFrontendDeveloperTeamMembersIds)
;=> [[:person/id 1] [:person/id 2] [:person/id 3]]
I created some function to help my need, they are almost working by I am not sure that they are best practices or not. Moreover still I giving :person/id manually.
(defn getPersonById [id] :docstring "get person by :person/id value"
(->> dbSample
(:person)
(filter #(= (:person/id %1) id))))
(defn getManagerPersonIdByManagerId [id] :docstring "get a manager name my given manager id"
(->> dbSample
(:employees/managers)
(filter #(= (:manager/id %) id))
(first)
(:manager/person)
(second)
))
(defn getPersonNameById [id]
(->> dbSample
(:person)
(filter #(= (:person/id %1) id))
(first)
(:name)
)
)
(defn getPersonManagerNameByPersonId [id] :docstring "get a person's manager name by given person id"
(->> id
(getPersonById)
(first)
(:managers)
(:manager/id)
(getManagerPersonIdByManagerId)
(getPersonNameById)
)
)
(getPersonManagerNameByPersonId 1)
;=> "rich"
CodePudding user response:
There are many ways to do this but you asked for guidance on best practices so here are a couple (but I make some assumptions)
Assumption 1: the person/id uniquely identifies a person. Probably right since you use first
. So rather than a list use a dict for person.
Similarly, managers and teams can be the dict you show without using a vector.
so data like:
(def db-sample {
:person {1 {:person/id 1 :name "dan" :surname "stone" :joindate "01.06.2022" :experience :experience/starter :loyalitylevel :loyality-level/zero-one-years :worktime :worktime/internship :managers {:manager/id 1}}
2 {:person/id 2 :name "dave" :surname "jhons" :joindate "04.04.2021" :experience :experience/medior :loyalitylevel :loyality-level/one-two-years :worktime :worktime/full-time :managers {:manager/id 1}}
3 {:person/id 3 :name "patrick" :surname "square pant" :joindate "09.01.2022" :experience :experience/senior :loyalitylevel :loyality-level/zero-one-years :worktime :worktime/part-time :managers {:manager/id 1}}
9 {:person/id 9 :name "rich" :surname "hickey" :joindate "04.04.2016" :experience :experience/lead :loyalitylevel :loyality-level/more-than-seven-years :worktime :worktime/part-time}
}
:employees/developerteam {:frontend [[:person/id 1] [:person/id 2] [:person/id 3]]}
:employees/managers {:manager/id 1 :manager/person [:person/id 9]}
:relations/experience {:experience/starter "0-1"
:experience/medior "1-3"
:experience/senior "3-6"
:experience/lead "6 "
}
:relations/loyalitylevel {:loyality-level/zero-one-years "0-1 year(s)"
:loyality-level/one-two-years "1-2 year(s)"
:loyality-level/three-five-years "3-5 year(s)"
:loyality-level/five-seven-years "5-7 year(s)"
:loyality-level/more-than-seven-years "7 year(s)"}
:relations/worktime {:worktime/full-time "full time"
:worktime/part-time "part time"
:worktime/internship "internship"}})
Now you can query much more of the data with simple get-in
, e.g. :
(defn get-person-by-id
"get person by :person/id value"
[id]
(get-in db-sample [:person id]))
Also note the position of the docstring and preference for kebab-case
over camelCase
. Databases change so the db should be passed into the queries to be pure functions.
CodePudding user response:
this task seems to be much alike the database inner join functionality, when you have to join :employees/developerteam -> :frontenders
with :person
then with :employees/managers
and then with :person
again to get the person (manager) to person (frontender) mapping. So for educational reasons i would propose to makeup this join function.. It could look like this:
(defn inner-join [[& {from :from alias1 :as}] & clauses]
(reduce (fn [join-agg [next-table & {:keys [as on]}]]
(for [a join-agg
b next-table
:let [res (assoc a as b)]
:when (on res)]
res))
(map #(hash-map alias1 %) from)
clauses))
For example, the first pair join of frontender to person would look like this:
(inner-join
[:from (get-in db-sample [:employees/developerteam 0 :frontend])
:as :frontender]
[(:person db-sample)
:as :person
:on (fn [{:keys [frontender person]}]
(= (second frontender) (:person/id person)))])
resulting to this:
({:person
{:person/id 1,
;; omitted
:managers #:manager{:id 1}},
:frontender [:person/id 1]}
{:person
{:person/id 2,
;; omitted
:managers #:manager{:id 1}},
:frontender [:person/id 2]}
{:person
{:person/id 3,
;; omitted
:worktime :worktime/part-time,
:managers #:manager{:id 1}},
:frontender [:person/id 3]})
The same manner you could continue until you get your solution:
(inner-join
[:from (get-in db-sample [:employees/developerteam 0 :frontend])
:as :frontender]
[(:person db-sample)
:as :person
:on (fn [{:keys [frontender person]}]
(= (second frontender) (:person/id person)))]
[(:employees/managers db-sample)
:as :person-manager
:on (fn [{:keys [person person-manager]}]
(= (-> person :managers :manager/id) (:manager/id person-manager)))]
[(:person db-sample)
:as :manager
:on (fn [{:keys [manager person-manager]}]
(= (-> person-manager :manager/person second)
(:person/id manager)))])
which results to:
({:person-manager #:manager{:id 1, :person [:person/id 9]},
:person
{:person/id 1,
:name "dan",
:surname "stone",
:joindate "01.06.2022",
:experience :experience/starter,
:loyalitylevel :loyality-level/zero-one-years,
:worktime :worktime/internship,
:managers #:manager{:id 1}},
:frontender [:person/id 1],
:manager
{:person/id 9,
:name "rich",
:surname "hickey",
:joindate "04.04.2016",
:experience :experience/lead,
:loyalitylevel :loyality-level/more-than-seven-years,
:worktime :worktime/part-time}}
{:person-manager #:manager{:id 1, :person [:person/id 9]},
:person
{:person/id 2,
:name "dave",
:surname "jhons",
:joindate "04.04.2021",
:experience :experience/medior,
:loyalitylevel :loyality-level/one-two-years,
:worktime :worktime/full-time,
:managers #:manager{:id 1}},
:frontender [:person/id 2],
:manager
{:person/id 9,
:name "rich",
:surname "hickey",
:joindate "04.04.2016",
:experience :experience/lead,
:loyalitylevel :loyality-level/more-than-seven-years,
:worktime :worktime/part-time}}
{:person-manager #:manager{:id 1, :person [:person/id 9]},
:person
{:person/id 3,
:name "patrick",
:surname "square pant",
:joindate "09.01.2022",
:experience :experience/senior,
:loyalitylevel :loyality-level/zero-one-years,
:worktime :worktime/part-time,
:managers #:manager{:id 1}},
:frontender [:person/id 3],
:manager
{:person/id 9,
:name "rich",
:surname "hickey",
:joindate "04.04.2016",
:experience :experience/lead,
:loyalitylevel :loyality-level/more-than-seven-years,
:worktime :worktime/part-time}})
now you can select only items you need, or remove intermediate stuff.. or whatever you want.