Json 在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实体 以下是一个基本模式

我的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)