Reputation: 5217
I'm having some trouble figuring out the pull API. I have two location entities. When I use pull
I only receive 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 incorrect pull expression but I see nothing glaringly wrong.
Upvotes: 3
Views: 1009
Reputation: 29958
To avoid subtle errors like this one, you may wish to try the Tupelo Datomic library.
Instead of using confusing symbols like "...", "[]", etc, Tupelo Datomic splits up the query syntax into four distinct functions. Here is an example usage:
; 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 pull
API is also supported if that format is better for your problem. Enjoy!
Upvotes: 1
Reputation: 1665
In the example you provide, you're using the "single tuple" find specification around the pull expression, which only returns a single tuple regardless of the number of entities matched by the query. You would run into the same problem if you specified a scalar return in find, i.e. with .
.
(1) The most straight forward way to correct this is to drop the find specification (this matches the form of your original query):
(d/q '[:find (pull ?e [:db/id :location/name])
:where [?e :location/name]]
db)
(2) You could 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 primary difference is that (1) will return a set of nested maps, whereas (2) will return a vectors of maps.
Upvotes: 3
Reputation: 5217
Looks like I was missing ...
.
(d/q '[:find [(pull ?e [:db/id
:location/name]) ...]
:where [?e :location/name]]
db)
=> [{:db/id 17592186045535, :location/name "Some Other Location"} {:db/id 17592186045420, :location/name "White House"}]
Upvotes: 4