2014-05-12 2 views
2

다른 사용자 유형을 따를 수있는 Datomic 데이터베이스에 사용자 엔티티 유형이 있습니다. 내 문제는 한 사용자가 이미 다음 또 다른 사용자가 다음에 올 때 온다 : Datomic에서 재귀 참조 연속화하기

User A follows user B and also User B follows user A 

나는 때문에 :user/follows-users 속성에 무한 재귀 (내가 추측하고있어)의 StackOverflowError가 얻을 (체셔 사용) 직렬화하려고

.

그런 방식으로 서로를 참조하는 두 개의 Datomic 엔티티를 (API의 json으로) 직렬화하면 어떻게 될까요? 여기

는 기본 스키마의 :

; 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) 

답변

1

링크 된 데이터 구조의 열망 확장은 모든 언어의 경우에 만 안전 그들은주기가 없습니다입니다. "주기가 발견 될 때까지 열심히 데이터를 확장 한 다음 (사용자 ID로) 링크로 전환"한다고 약속 한 API는 결코 확장되지 않고 항상 응답의 모든 링크를 따르기에 충분한 사용자를 반환 한 것보다 안정적으로 소비하기가 어려울 수 있습니다 . 예를 들어 위의 요청은 JSON을 반환 할 수 있습니다.

[{"id": -100000, 
    "username": "Cheech", 
    "follows-users": [-200000]} 
{"id": -200000, 
    "username": "Chong", 
    "follows-users": [-100000]}] 

사용자 그래프의 집합을 한 세트로 축소하여 선택한 사용자의 목록을 찾을 수 있습니다.

0

저는 Datomic에 n00b가 약간 있습니다. @ 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) 
관련 문제