Datomic 新手问题 - 当一个事实发生变化时对相关事实进行建模
Datomic newbie question - modelling related facts when one fact changes
如果我有一个客户实体,并且他们在时间 t1 从具有以下事实的地址移动:
- address_line_1 = "唐宁街 10 号"
- address_line_2 = "Westminster"
- 城市="London"
到新地址和时间 t2,这些事实:
- address_line_1 = "1600 Pennsylvania Ave NW"
- 城市="Washington DC"
如何避免 t2 之后的地址看起来像:
- address_line_1 = "1600 Pennsylvania Ave NW"
- address_line_2 = "Westminster"
- 城市="Washington DC"
我能想到的选项:
- 在 t2 断言 address_line_2 = "" 以重置或清除它。
- 将地址作为它自己的实体指向一个新地址实体,该实体只有两个事实:address_line_1 = "1600 Pennsylvania Ave NW" 和 city = "Washington DC" 断言。
- 在 t2 断言一个新事实,例如 "moved_house" = true 来表示他们的地址不同。
我的想法:
- 选项 1 似乎依赖于 "knowing" 之前一直设置的可能不再正确的内容,因此您可以将其删除。
- 选项 2 似乎最好 - 但确实意味着定义的网络比我预期的要多。
- 选项 3 看起来很糟糕!
任何其他人对此的想法将不胜感激:)
您可以使用选项 2 作为组件实体。
https://support.cognitect.com/hc/en-us/articles/215581418-Component-Attributes?mobile_site=true
这是一个示例:
;; schema
;;
(d/transact conn [{:db/ident :client/address
:db/cardinality :db.cardinality/one
:db/valueType :db.type/ref
:db/isComponent true}
{:db/ident :address/line1
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one}
{:db/ident :address/country
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one}])
;; create a new client with address - 1 Main Street
;;
(d/transact conn [{:db/id (d/tempid :db.part/user -1)
:client/address {:address/line1 "1 Main Street"
:address/country "USA"}}])
;; datomic will return you two entity id. One is for :client/address
;; and another one for :address/line1 and :address/country
;;
(d/q '[:find (pull ?e [*])
:where [?e :client/address]]
(d/db conn))
;; => [[{:db/id 17592186045418, :client/address {:db/id 17592186045419, :address/line1 "1 Main Street", :address/country "USA"}}]]
;; now update its client address to 9 Kings Road.
;;
(d/transact conn [{:db/id 17592186045418
:client/address {:address/line1 "9 Kings Road"}}])
;; 17592186045418 will then have a :client/address
;; pointing to a new entity with the new address
;;
(d/q '[:find (pull ?e [*])
:where [?e :client/address]]
(d/db conn))
;; => [[{:db/id 17592186045418, :client/address {:db/id 17592186045421, :address/line1 "9 Kings Road"}}]]
如果我有一个客户实体,并且他们在时间 t1 从具有以下事实的地址移动:
- address_line_1 = "唐宁街 10 号"
- address_line_2 = "Westminster"
- 城市="London"
到新地址和时间 t2,这些事实:
- address_line_1 = "1600 Pennsylvania Ave NW"
- 城市="Washington DC"
如何避免 t2 之后的地址看起来像:
- address_line_1 = "1600 Pennsylvania Ave NW"
- address_line_2 = "Westminster"
- 城市="Washington DC"
我能想到的选项:
- 在 t2 断言 address_line_2 = "" 以重置或清除它。
- 将地址作为它自己的实体指向一个新地址实体,该实体只有两个事实:address_line_1 = "1600 Pennsylvania Ave NW" 和 city = "Washington DC" 断言。
- 在 t2 断言一个新事实,例如 "moved_house" = true 来表示他们的地址不同。
我的想法:
- 选项 1 似乎依赖于 "knowing" 之前一直设置的可能不再正确的内容,因此您可以将其删除。
- 选项 2 似乎最好 - 但确实意味着定义的网络比我预期的要多。
- 选项 3 看起来很糟糕!
任何其他人对此的想法将不胜感激:)
您可以使用选项 2 作为组件实体。
https://support.cognitect.com/hc/en-us/articles/215581418-Component-Attributes?mobile_site=true
这是一个示例:
;; schema
;;
(d/transact conn [{:db/ident :client/address
:db/cardinality :db.cardinality/one
:db/valueType :db.type/ref
:db/isComponent true}
{:db/ident :address/line1
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one}
{:db/ident :address/country
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one}])
;; create a new client with address - 1 Main Street
;;
(d/transact conn [{:db/id (d/tempid :db.part/user -1)
:client/address {:address/line1 "1 Main Street"
:address/country "USA"}}])
;; datomic will return you two entity id. One is for :client/address
;; and another one for :address/line1 and :address/country
;;
(d/q '[:find (pull ?e [*])
:where [?e :client/address]]
(d/db conn))
;; => [[{:db/id 17592186045418, :client/address {:db/id 17592186045419, :address/line1 "1 Main Street", :address/country "USA"}}]]
;; now update its client address to 9 Kings Road.
;;
(d/transact conn [{:db/id 17592186045418
:client/address {:address/line1 "9 Kings Road"}}])
;; 17592186045418 will then have a :client/address
;; pointing to a new entity with the new address
;;
(d/q '[:find (pull ?e [*])
:where [?e :client/address]]
(d/db conn))
;; => [[{:db/id 17592186045418, :client/address {:db/id 17592186045421, :address/line1 "9 Kings Road"}}]]