API Datomic Pull API retrieves only one object
I am having trouble figuring out the pull API. I have two location objects. When I use pull
I only get one.
(ns some-ns.core
(:require [datomic.api :as d]))
(d/q '[:find ?e
:where [?e :location/name]]
db)
=> #{[17592186045535] [17592186045420]} ; two results
(d/q '[:find [(pull ?e [:db/id
:location/name])]
:where [?e :location/name]]
db)
=> [{:db/id 17592186045535, :location/name "Some Other Location"}] ; one result
I suspect I might be using the wrong pull expression, but I don't see anything terrible.
source to share
In the example you provide, you use "single tuple" to find a BOM around a pull expression that only returns one tuple regardless of the number of objects that match the request. You would run into the same problem if you specified a scalar return in find, i.e. With help .
.
(1) The easiest way to fix this is to drop the search spec (this matches the shape of your original query):
(d/q '[:find (pull ?e [:db/id :location/name]) :where [?e :location/name]] db)
(2) You can also, as in your own answer, specify a collection in find:
(d/q '[:find [(pull ?e [:db/id :location/name]) ...] :where [?e :location/name]] db)
The main difference is that (1) will return a set of nested maps, while (2) will return vectors of maps.
source to share
To avoid subtle mistakes like this, you can try the Duptom Tupelo library.
Instead of using confusing characters like "...", "[]", etc., Tupelo Datomic splits the query syntax into four different functions. Here's a usage example:
; If you want just a single attribute as output, you can get a set of values (rather than a set of
; tuples) using td/query-set. As usual, any duplicate values will be discarded.
(let [names (td/query-set :let [$ (live-db)]
:find [?name] ; <- a single attr-val output allows use of td/query-set
:where [ [?eid :person/name ?name] ] )
cities (td/query-set :let [$ (live-db)]
:find [?loc] ; <- a single attr-val output allows use of td/query-set
:where [ [?eid :location ?loc] ] )
]
(is (= names #{"Dr No" "James Bond" "M"} )) ; all names are present, since unique
(is (= cities #{"Caribbean" "London"} ))) ; duplicate "London" discarded
The API is pull
also supported if that format is better for your problem. Enjoy!
source to share