[英]how to work with complex data in Clojure edn/map
(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"}}
)
大家好,我開始學習 Clojure 並嘗試做一些練習以更好地理解它。 如何找到前端團隊成員的經理姓名? 我用你可以在底部看到的 function 得到他們的“:person/id”。 現在我想知道如何才能找到他們經理的名字。
我剛剛創建了一個示例數據(它有點復雜,但我切斷了額外的復雜性)來學習如何獲取數據和在數據內部移動。 我想向我的第二個功能的 output 提供輸入,我想看看這些人經理是誰。 我不知道這是否容易或可能。
(defn getFrontendDeveloperTeamMembersIds [] :docstring "get frontend developer team members references"
(->> dbSample
(:employees/developerteam)
(first)
(:frontend)
)
)
(getFrontendDeveloperTeamMembersIds)
;=> [[:person/id 1] [:person/id 2] [:person/id 3]]
我創建了一些 function 來滿足我的需求,它們幾乎可以正常工作我不確定它們是否是最佳實踐。 此外,我仍然手動 giving:person/id 。
(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"
有很多方法可以做到這一點,但你要求獲得最佳實踐指導,所以這里有幾個(但我做了一些假設)
假設 1:person/id 唯一標識一個人。 可能是正確的,因為您first
使用 . 因此,與其使用列表,不如使用 person 的字典。
同樣,經理和團隊可以是您在不使用向量的情況下顯示的命令。
所以數據如下:
(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"}})
現在您可以使用簡單get-in
查詢更多數據,例如:
(defn get-person-by-id
"get person by :person/id value"
[id]
(get-in db-sample [:person id]))
另請注意文檔字符串的 position 以及對 kebab kebab-case
而非camelCase
的偏好。 數據庫發生變化,因此 db 應該作為純函數傳遞到查詢中。
這個任務似乎很像數據庫內部連接功能,當你必須加入:employees/developerteam ->:frontenders
與:person
然后與:employees/managers
然后與:person
再次獲得人(經理)到人(前端)映射。 所以出於教育原因,我建議加入 function。它可能看起來像這樣:
(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))
例如,frontender 到 person 的第一對連接看起來像這樣:
(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)))])
結果是:
({: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]})
您可以以相同的方式繼續,直到獲得解決方案:
(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)))])
結果是:
({: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}})
現在你可以 select 只有你需要的項目,或刪除中間的東西..或任何你想要的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.