Json 在Datomic中序列化递归引用
我的Datomic数据库中有一个用户实体类型,可以遵循其他用户类型。当一个用户跟踪另一个已经跟踪他们的用户时,我的问题就会出现:Json 在Datomic中序列化递归引用,json,recursion,clojure,datomic,Json,Recursion,Clojure,Datomic,我的Datomic数据库中有一个用户实体类型,可以遵循其他用户类型。当一个用户跟踪另一个已经跟踪他们的用户时,我的问题就会出现: User A follows user B and also User B follows user A 当我尝试序列化(使用Cheshire)时,我得到了一个StackOverflower错误,因为(我猜)在:user/follows users属性上存在无限递归 我将如何序列化(对于API为json)以这种方式相互引用的两个Datomic实体 以下是一个基本模式
User A follows user B and also User B follows user A
当我尝试序列化(使用Cheshire)时,我得到了一个StackOverflower错误,因为(我猜)在:user/follows users
属性上存在无限递归
我将如何序列化(对于API为json)以这种方式相互引用的两个Datomic实体
以下是一个基本模式:
; schema
[{:db/id #db/id[:db.part/db]
:db/ident :user/username
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db/unique :db.unique/identity
:db.install/_attribute :db.part/db}
{:db/id #db/id[:db.part/db]
:db/ident :user/follows-users
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/many
:db.install/_attribute :db.part/db}
; create users
{:db/id #db/id[:db.part/user -100000]
:user/username "Cheech"}
{:db/id #db/id[:db.part/user -200000]
:user/username "Chong"}
; create follow relationships
{:db/id #db/id[:db.part/user -100000]
:user/follows-users #db/id[:db.part/user -200000]}
{:db/id #db/id[:db.part/user -200000]
:user/follows-users #db/id[:db.part/user -100000]}]
一旦在repl上设置了数据库等:
user=> (use '[cheshire.core :refer :all])
nil
user=> (generate-string (d/touch (d/entity (d/db conn) [:user/username "Cheech"])))
StackOverflowError clojure.lang.RestFn.invoke (RestFn.java:433)
链接数据结构的渴望扩展只有在任何语言中都是安全的,只要它们是无循环的。承诺“只在找到一个周期之前急切地扩展数据,然后切换到链接(按用户id)”的api可能比从未扩展且始终返回足够多用户以跟踪响应中的所有链接的api更难可靠地使用。例如,上面的请求可以返回JSON:
[{"id": -100000,
"username": "Cheech",
"follows-users": [-200000]}
{"id": -200000,
"username": "Chong",
"follows-users": [-100000]}]
通过将用户行走图简化为一个集合,可以找到所选用户的列表。我对Datomic有点陌生,我确信一定有一种更惯用的方法来完成@arthur ulfeldt上面建议的操作,但万一其他人正在寻找如何将Datomic EntityMaps序列化为json的快速指针,其中存在自引用引用,下面是解决我的问题的代码:
(defn should-pack?
"Returns true if the attribute is type
ref with a cardinality of many"
[attr]
(->>
(d/q '[:find ?attr
:in $ ?attr
:where
[?attr :db/valueType ?type]
[?type :db/ident :db.type/ref]
[?attr :db/cardinality ?card]
[?card :db/ident :db.cardinality/many]]
(d/db CONN) attr)
first
empty?
not))
(defn make-serializable
"Stop infinite loops on recursive refs"
[entity]
(def ent (into {} entity))
(doseq [attr ent]
(if (should-pack? (first attr))
(def ent (assoc ent
(first attr)
(map #(get-entity-id %) (first (rest attr)))))))
ent)