clojure - 如何在 Datomic 中实现排序对多关系?

标签 clojure database-schema datomic

Datomic 中没有开箱即用的模式特性来对多对多关系中的子实体进行排序,但这是一个非常常见的要求。谷歌搜索发现了一些解决方案,所以我想在这里盘点需求和解决方案的变化,并希望来自社区的评论。

可能的要求

  • R1:子实体的小数量(N)(不确定小/大是什么
    阈值应该是)
  • R2:大量子实体
  • R3:单亲子女
  • R4:多亲子女
  • R5:递归子节点,即存储在 Datomic 中的树

  • 我的特定用例是 R1 + R3 + R5,我怀疑它很常见,但我想尽可能多地枚举,以便将来可以成为其他人的有用引用。

    解决方案
  • S1:具有“位置”属性的嵌套组件实体,例如Datofu
  • S2:如 using transactor fns here 所述,为每个 child 添加自定义“位置”属性并在 this post
  • S3:在 datomic-linklist 中实现的每个子实体上使用“next”属性的链表
  • S4:将边表示为 described in this post 的单独包装实体

  • 问题

    每个解决方案似乎都有挑战。我能想到的有:
  • P1:为插入、删除或移动操作保持恒定时间操作。有人建议对“位置”值使用小数,以避免在重新排序时必须更新所有子项
  • P2:支持多父关系与排序
  • P3:随着排序或成员资格的变化,维护存储顺序的位置或边的复杂性。
  • P4:更改“位置”属性会影响子实体的隐含“上次更改”日期,但实际上并未更改
  • P5:通过包装实体连接时,查询/拉取(特别是递归查询)会变得困难

  • 对于我的树用例,我不关心 P2 和 P1 不是一个大问题,因为 N 通常很低

    所有这些研究都没有帮助我弄清楚哪种解决方案最适合我的树用例,但我倾向于 S2。自然地,最不复杂的是我的目标,但我怀疑所有的解决方案都会很复杂。

    问题 : 你有解决这个问题的经验吗?你能分享什么来帮助别人做出决定?我会在上面添加更多的 R、S 和 P,正如他们指出的那样。我(和许多其他人)将非常感谢任何反馈。

    similar question几年前被问到,但那里没有发生太多事情。

    最佳答案

    这实际上取决于您的实际用例(并且您可能同时在单个数据库中拥有多个不同的用例)。

    首先,选择one-to-manymany-to-many亲子关系:

  • one-to-many意味着您可以将额外的属性正确地粘贴到子实体上,避免在额外的 :db/id 上花费宝贵的数据, :my.domain/guid , :ordinal/ref属性,以及历史大小。
  • many-to-many意味着你必须有单独的实体来跟踪 child 之间的排序。

  • 此时,您可能仍想选择单独的实体,以免弄乱一些 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}}]} 
    

    缺点是:您需要保持两者同步以避免孤儿序数或下落不明的 child 。

    最后,linked list对比 position values更多的是品味问题。然而,positional values有更大的tx-data足迹(例如,在 10 个元素列表中的第 0 个位置插入单个元素需要 10 个额外的数据,在添加新元素的基础上每 10 个元素接触一次)。

    我认为,唯一的劣等解决方案 - 包装 child ( parent-wrapper-child ),它从您那里消除了递归拉动模式,并以其他方式妨碍了您。

    现在回到您的用例:
    single-parent + recursive queries = idxnext child 的属性。

    关于clojure - 如何在 Datomic 中实现排序对多关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44645938/

    相关文章:

    mysql - 了解数据库模式

    mysql - 如果两个应用程序都具有多数据库架构,如何将不同应用程序的数据存储在同一个本地MySQL实例中?

    sql - 两人游戏的数据库架构

    clojure - 从 Datomic 检索最近的实体

    couchdb - 如何维护 CouchDB、BigCouch 或其他开源数据库中的历史记录(例如 VCS)?

    clojure 部分说明

    haskell - 这些用柯里化(Currying)和转换器实现的函数有什么区别?

    Clojure 将字符串的 PersistentVector 转换为关键字的 PersistentVector

    clojure - 将Clojure Spec与Datomic实体一起使用

    java - Systemd: '_JAVA_OPTIONS' 节中的未知左值 'Service'