Datomic's new Pull API is a declarative way to make hierarchical selections of information about entities. You supply a pattern to specify which attributes of the entity (and nested entities) you want to pull, and db.pull returns a map for each entity.
Pull API vs. Entity API
The Pull API has two important advantages over the existing
Entity API:
Pull uses a declarative, data-driven spec, whereas Entity encourages building results via code. Data-driven specs are easier to build, compose, transmit and store. Pull patterns are smaller than entity code that does the same job, and can be easier to understand and maintain.
Pull API results match standard collection interfaces (e.g. Java maps) in programming languages, where Entity results do not. This eliminates the need for an additional allocation/transformation step per entity.
Wildcards
A pull pattern is a list of attribute specifications. If you want all attributes, you can use the wildcard (*) specification along with an
entity identifier. (In the examples below, entity identifiers such as
led-zeppelin are variables defined in the complete code examples in
Clojure and
Java.)
;; Clojure API
(d/pull db '[*] led-zeppelin)
;; Java API
db.pull("[*]", ledZeppelin)
A pull result is a map per entity, shown here in
edn:
;; result
{:artist/sortName "Led Zeppelin",
:artist/name "Led Zeppelin",
:artist/type {:db/id 17592186045746},
:artist/country {:db/id 17592186045576},
:artist/gid #uuid "678d88b2-87b0-403b-b63d-5da7465aecc3",
:artist/endDay 25,
:artist/startYear 1968,
:artist/endMonth 9,
:artist/endYear 1980,
:db/id 17592186050305}
Attributes
You can also specify the attributes you want explicitly, as with
:artist/name and
:artist/gid below:
;; pattern
[:artist/name :artist/gid]
;; input
led-zeppelin
;; result
{:artist/gid #uuid "678d88b2-87b0-403b-b63d-5da7465aecc3",
:artist/name "Led Zeppelin"}
The underscore prefix reverses the direction of an attribute, so
:artist/_country pulls all the artists for a particular country:
;; pattern
[:artist/_country]
;; input
greatBritain
;; result
{:artist/_country [{:db/id 17592186045751}
{:db/id 17592186045755}
...]}
Components
Datomic component attributes are pulled recursively by default, so the :release/media pattern below automatically returns a release's tracks as well:
;; pattern
[:release/media]
;; input
darkSideOfTheMoon
;; result
{:release/media
[{:db/id 17592186121277,
:medium/format {:db/id 17592186045741},
:medium/position 1,
:medium/trackCount 10,
:medium/tracks
[{:db/id 17592186121278,
:track/duration 68346,
:track/name "Speak to Me",
:track/position 1,
:track/artists [{:db/id 17592186046909}]}
{:db/id 17592186121279,
:track/duration 168720,
:track/name "Breathe",
:track/position 2,
:track/artists [{:db/id 17592186046909}]}
{:db/id 17592186121280,
:track/duration 230600,
:track/name "On the Run",
:track/position 3,
:track/artists [{:db/id 17592186046909}]}
...]}]}
Map Specifications
Instead of just an attribute name, you can use a nested map specification to pull related entities. The pattern below pulls the
:db/id and
:artist/name of each artist:
;; pattern
[:track/name {:track/artists [:db/id :artist/name]}]
;; input
ghostRiders
;; result
{:track/artists [{:db/id 17592186048186, :artist/name "Bob Dylan"}
{:db/id 17592186049854, :artist/name "George Harrison"}],
:track/name "Ghost Riders in the Sky"}
And of course everything nests arbitrarily, in case you need the release's medium's track's names and artists:
;; pattern
[{:release/media
[{:medium/tracks
[:track/name {:track/artists [:artist/name]}]}]}]
;; input
concertForBanglaDesh
;; result
[{:medium/tracks
[{:track/artists
[{:artist/name "Ravi Shankar"} {:artist/name "George Harrison"}],
:track/name "George Harrison / Ravi Shankar Introduction"}
{:track/artists [{:artist/name "Ravi Shankar"}],
:track/name "Bangla Dhun"}]}
{:medium/tracks
[{:track/artists [{:artist/name "George Harrison"}],
:track/name "Wah-Wah"}
{:track/artists [{:artist/name "George Harrison"}],
:track/name "My Sweet Lord"}
{:track/artists [{:artist/name "George Harrison"}],
:track/name "Awaiting on You All"}
{:track/artists [{:artist/name "Billy Preston"}],
:track/name "That's the Way God Planned It"}]
...]}
Try It Out
..