Val*_*nck 7 database-design datomic
我正在寻找关于在Datomic中建模某些多对关系的方法的反馈.
假设我想为一个人有一个最喜欢的电影列表的域设计Datomic模式.举例来说,John
最喜欢的电影是Gladiator
,Star Wars
和Fight Club
.
在Datomic中对此进行建模的最明显的架构是具有基数多属性,例如:
#{["John" :person/favorite-movies "Gladiator"]
["John" :person/favorite-movies "Star Wars"]
["John" :person/favorite-movies "Fight Club"]}
Run Code Online (Sandbox Code Playgroud)
这种方法可以很容易地从列表中添加或删除电影(简单地使用:db/add
和:db/retract
),但我发现重置整个电影列表是不切实际的- 你基本上需要计算旧列表和新列表之间的差异,并且在事务函数中运行.当列表的元素不是标量时,这会变得更糟.
作为替代方法,我正在考虑使用set实体引入间接:
#{["John" :person/favorite-movies 42]
[42 :set.string/contains "Gladiator"]
[42 :set.string/contains "Star Wars"]
[42 :set.string/contains "Fight Club"]}
Run Code Online (Sandbox Code Playgroud)
使用这种方法,:person/favorite-movies
是一个基数 - 一,ref-typed属性,并且:set.string/contains
是基数多,字符串类型的属性.然后重置列表只需创建一个新的集合实体:
[{:db/id "John"
:person/favorite-movies {:db/id (d/tempid :db.part/user)
:set.string/contains ["Gladiator"
"The Lord of the Rings"
"A Clockwork Orange"
"True Romance"]}}]
Run Code Online (Sandbox Code Playgroud)
这种建模到多种关系的方法是否存在已知的局限性?
在关系是ref-typed而不是标量类型的情况下研究这个问题更相关,因为在Datomic中出现了一些ref-typed属性的问题.
研究一个用例,其中关系的"重置"操作更有意义,这对于"最喜欢的电影"来说并非如此.
例如:甲形式与复选框,其中用户可以提供Answer
到一个Question
通过选择一组的Option
第 用户可以将她更新Answer
为Question
.目标是建立Answer - Option
关系模型.
此信息模型的规范Datomic架构将是:
:answer/id
:答案的唯一ID(标量类型,唯一标识):option/id
:选项的唯一ID(标量类型,唯一标识):answer/selectedOptions
(ref-typed,cardinality-many)经过几个月的尝试,我得出以下结论。
两种策略(A - 使用直接属性 vs B - 使用中介、一次性实体)在阅读和写作方面都有实际的优点和缺点,正如问题和Francis Avila 的答案中所示。但恕我直言,最重要的原则是:模式应该主要由领域模型决定,而不是由读写模式决定。
是否存在适合策略 B 的领域模型?我相信是这样。
例如,在问题中提出的问题/选项/答案示例域中,将答案集解释为一个有凝聚力的整体而不是单独的单个事实可能更有意义。向中间实体添加:submittedTime
即时类型属性,您现在已经对答案的修订版进行了建模(您不想依赖 Datomic 历史来对其进行建模)。
笔记:
使用策略A,实现“重置”操作需要事务函数;由于与实体生命周期相关的棘手问题(“该实体是否已经存在”),在最一般的情况下编写这样的事务函数并不容易。我对此的最佳尝试可以在 Datofu 图书馆中找到。