Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nesting structures With Datomic

Using Datomic, I'm trying to think of how can I nest a list within a list?

An example Clojure data structure would be something (see fig.1). I know that Datomic has the notion of references (ex. in fig.2). But those just look like scalar types, not objects (per se).

  [{:id 0,
    :symbol DDD,
    :company 3D Systems Corporation,
    :price-difference 1.3100000000000023,
    :event-list [{high 35.11,
                  tickerId 0,
                  WAP 34.491,
                  open 35.07,
                  date 20130426,
                  count 3403,
                  low 33.8,
                  hasGaps false,
                  close 34.53,
                  field historicalData,
                  volume 8667,
                  type historicalData}]}]

fig.1

 {:db/id #db/id[:db.part/db]
  :db/ident :district/region
  :db/valueType :db.type/ref
  :db/cardinality :db.cardinality/one
  :db/doc "A district region enum value"
  :db.install/_attribute :db.part/db}

 ;; district/region enum values
 [:db/add #db/id[:db.part/user] :db/ident :region/n]
 [:db/add #db/id[:db.part/user] :db/ident :region/ne]
 [:db/add #db/id[:db.part/user] :db/ident :region/e]
 [:db/add #db/id[:db.part/user] :db/ident :region/se]
 [:db/add #db/id[:db.part/user] :db/ident :region/s]
 [:db/add #db/id[:db.part/user] :db/ident :region/sw]
 [:db/add #db/id[:db.part/user] :db/ident :region/w]
 [:db/add #db/id[:db.part/user] :db/ident :region/nw]

fig.2

[EDIT]

Actually, I think I might have found the answer here. I was going through the Day-Of-Datomic code base, and found the example below. But I'm still not clear on what explicitly ties the :comments namespace to the :comment/body (or :comment/author) namespace(s). Does Datomic just use convention to link :comments to :comment ?

  ;; comments
  [{:db/id #db/id[:db.part/db]
  :db/ident :comments
    :db/valueType :db.type/ref
    :db/cardinality :db.cardinality/many
    :db/isComponent true
    :db.install/_attribute :db.part/db}
   {:db/id #db/id[:db.part/db]
    :db/ident :comment/body
    :db/valueType :db.type/string
    :db/cardinality :db.cardinality/one
    :db.install/_attribute :db.part/db}
   {:db/id #db/id[:db.part/db]
    :db/ident :comment/author
    :db/valueType :db.type/ref
    :db/cardinality :db.cardinality/one
    :db.install/_attribute :db.part/db}]

fig.1

like image 445
Nutritioustim Avatar asked Apr 26 '13 18:04

Nutritioustim


1 Answers

You can't directly persist multi-dimensional lists/vectors but you can use a linking entity to accomplish something similar:

;; sample attributes
[{:db/id #db/id[:db.part/db]
  :db/ident :some/ref-value
  :db/valueType :db.type/ref
  :db/isComponent true
  :db/cardinality :db.cardinality/many  
  :db.install/_attribute :db.part/db}
  {:db/id #db/id[:db.part/db]
  :db/ident :some/list-value
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/many
  :db.install/_attribute :db.part/db}]

;; [["a" "b" "c"]["d" "e" "f"]]
 [{:db/id #db/id[:db.part/user -1]
 :some/list-value ["a" "b" "c"]}
 {:db/id #db/id[:db.part/user -2]
 :some/list-value ["d" "e" "f"]} 
 {:db/id #db/id[:db.part/user]
 :some/ref-value [#db/id[:db.part/user -1] #db/id[:db.part/user -2]]}]

Note that you can use negative numbers to link entities together. They will be replaced by real entity ids when you transact them.

EDIT: Starting with version 0.8.4020, Datomic supports nested component entities (containment relationships specified by :db/isComponent) as part of the transaction data. e.g.

 ;; [["a" "b" "c"]["d" "e" "f"]]
 [{:db/id #db/id[:db.part/db]
   :some/ref-value [{:some/list-value ["a" "b" "c"]}
                    {:some/list-value ["d" "e" "f"]}]}]

The nested maps expand into two sub-entities, both created in the same partition as the container/parent entity. For a full code sample, see https://gist.github.com/a2ndrade/5820364

like image 196
a2ndrade Avatar answered Sep 24 '22 03:09

a2ndrade