对于这种模式,Datomic土地中更具惯用性的选择是什么?

Hen*_*rik 6 clojure datomic

我有一个问题,关于什么是Datomic的更惯用的架构.

假设我们有实体User,Post并且Topic.

Post可以属于Topic,User和其他Post(回复).现在,我应该

a)创建一个:posts属性,它只是一个Posts 列表,并将其注入需要引用多个Posts的每个实体中?

要么

b)建立更明确的关系,例如a Post有一个:post/author属性是对用户的引用,也许是一个:post/belongs-to可以引用一个Topic或另一个的属性Post

观察:如果我做b,我似乎得到更多的语义关系.我可以举例来说(:post/_author user-entity),它更能描述他们关系网的性质而不是(:posts user-entity)(因为,它User具有:posts什么意义?是那些被User收藏Post的,是作者Post的,还是什么?)

b的另一个副作用是我可以创建一个新的Post而不会改变任何其他实体.如果我做一个,我需要创建Post并把它插入到:posts的属性User,需要两个操作,而不是一个.

不过,我有一个感觉,一个可能是做的更地道的方式.例如,似乎更容易看到属性列表如何:posts随着时间的推移而发生变化,我是否应该这样做,如果User引用:posts而不是通过属性Post引用.User:post/author

什么是可取的,为什么?

Ale*_*ard 6

您的选项(b)基本上是惯用的,也是唯一的方法.

所有数据库模式仅被编码为属性可以在实体 - 属性 - 值数据(EAV)的结构中采用的值.

请参阅http://docs.datomic.com/schema.html-从文档中获取的关键命题是:

每个Datomic数据库都有一个模式,用于描述可与实体关联的属性集.模式仅定义属性本身的特征.它没有定义哪些属性可以与哪些实体相关联.

实体本身是高度抽象的(内部只是数字),实体的所有有趣属性都被编码为属性值断言.实体未输入!您可以通过您为其声明的属性创建实体的语义,例如:user/firstname,:post/title,:post/content,:topic/description等.这就是您真正想要命名属性的原因.

一个特殊情况是属性类型:db.type/ref,其中EAV中的"V"值本身就是另一个实体.这就是在实体之间创建语义关联的原因.您为每个属性指定一个"名称"(作为a :db/ident)以捕获E < - > E连接实际意味着什么.所以,你可以拥有的属性:db.type/ref:db/ident":交/作者".

请注意,所有:db.type/ref属性本质上都是双向的,因此如果Eu是表示用户Ep的实体并且是表示帖子的实体,则以下在数据创建和查询中都是等效的:

[Ep :post/author  Eu]
[Eu :post/_author Ep]
Run Code Online (Sandbox Code Playgroud)

所有实体关系只是更多的属性断言是非常灵活的.如果你以后想要添加喜欢的帖子的概念,那只是另一个属性:db.type/ref.使用:db/ident诸如":user/favorites"之类创建它,并断言预先存在的用户和帖子(具有不同的用户实体作为作者)之间的连接.

[aUser :user/favorites somePost]
Run Code Online (Sandbox Code Playgroud)

没有集合值属性的概念,所以你在(a)中的建议在数据组中是不能正确表达的.您将使用查询来聚合帖子.删除后将通过撤回实体本身来建模.这样一个收回的帖子将在数据库历史记录中保持可见.

这确实对如何为实体列表指定订单提出了挑战.您需要使用"自然"排序,例如帖子的日期(在数据组事务中捕获或作为帖子的显式属性)或使用基于显式属性值的排序,例如通过:post/up-投票数字属性.

如果您需要实体的语义分组,其中"子实体"仅有意义并且仅作为更大的事物的一部分存在 - 例如订单中的行项目实体 - 那么请参阅数据组件.