Datomic中没有开箱即用的架构功能,用于在多对多关系中对子实体进行排序,但这是一个非常常见的要求。谷歌搜索已经发现了一些解决方案,所以我想在这里列出需求和解决方案的变化,希望得到社区的评论。
可能的要求
我的特定用例是R1 + R3 + R5,我怀疑它很常见,但我想尽可能多地枚举,以便将来可能成为其他人的有用参考。
解决方案
问题
每个解决方案似乎都有挑战。我能想到的是:
对于我的树用例,我不关心P2和P1不是一个大问题,因为N通常很低
所有这些研究都没有帮助我找清楚哪种解决方案最适合我的树用例,但我倾向于S2。当然,最不复杂的是我的目标,但我怀疑所有解决方案都很复杂。
问题:您对此问题有什么经验吗?您可以分享哪些内容可以帮助其他人做出决定?我们会在指出时添加更多R,S和P。我(以及其他许多人)会非常感谢任何反馈。
几年前曾问过similar question但在那里发生的事情并不多。
答案 0 :(得分:0)
这实际上取决于您的实际用例(并且您可能同时在单个DB中有几个不同的用例)。
首先,在one-to-many
和many-to-many
亲子关系中进行选择:
one-to-many
表示您可以将额外的属性权限放在子实体上,避免在额外的:db/id
,:my.domain/guid
,:ordinal/ref
属性以及历史记录大小上花费宝贵的数据。< / LI>
many-to-many
表示您必须有独立的实体来跟踪孩子之间的排序。此时,你仍然可能想要选择单独的实体,以避免在子实体上弄乱一些latest change date
统计/订阅(如果有的话)。在语义上,改变了孩子的顺序意味着父母实体已经改变,而不是儿童实体。
接下来,将recursive pull patterns and queries
问题排除在外。如果你选择了attribute on child
- 你已经很好了。
如果您使用separate entity
,请将有序实体保留在父实体的单独属性中:
{:foo/bars [{:db/id 4}
{:db/id 2}]
:foo/bars-order [{:db/id 9 :ordinal/idx 0 :ordinal/ref {:db/id 2}}
{:db/id 8 :ordinal/idx 1 :ordinal/ref {:db/id 4}}]}
缺点是:你需要保持同步以避免孤儿或不明的孩子。
最后,linked list
与position values
的关系更多的是品味问题。但是,positional values
具有更大的tx-data
足迹(例如,在10个元素列表的位置0处插入单个元素需要10个额外的数据,在添加新元素的顶部触及每10个元素。)
我认为,唯一的劣质 - 无关紧要的解决方案 - 包装儿童(parent-wrapper-child
),它会带走你的递归拉动模式,并以其他方式阻碍。
现在回到你的用例:
孩子的single-parent
+ recursive queries
= idx
或next
属性。
答案 1 :(得分:0)
为了将来的参考,我通过使用带有拉链的Datomic Linked List包装器获得了我的要求(有序树存储)的成功。链接列表代码有一些错误,我很快就会将它们/ /修复/部署到clojars。
此解决方案非常简单,并且具有更改操作的恒定时间,因此性能良好。
一个挑战是多个有序的子关系。链表代码假设每个实体有一个有序列表,在我的情况下,我需要1个树子列表,但更多列表用于其他数据。我已经解决了这个问题,但如果您的要求相似,则需要考虑这个问题。
如果其他有用的观察结果来自这个原型,我会发表进一步的评论。
答案 2 :(得分:0)
在我对问题here的答复中,对2019年6月Datomic的新功能有一个针对此问题的新解决方案。