[{:db/id 1, :co-ordinate {:x 0, :y 1, :z 2}}, {:db/id 2, :co-ordinate {:x 1, :y 1, :z 2}}]
How would I find all entities with a y co-ordinate of 1? Is there a way I can bind the internals of :co-ordinate as a part of a query?[:find ?e
:where [?e :co-ordinate ?x] [(= 1 (:y ?x))]]
doesn't work, obviouslyThe issue is that (:y ?x) is not part of your predicate, and not evaluated. One way to solve this is like so:
(let [conn (d/create-conn)]
(d/transact! conn [{:db/id 1, :co-ordinate {:x 0, :y 1, :z 2}}, {:db/id 2, :co-ordinate {:x 1, :y 1, :z 2}}])
(prn (d/q '{:find [?e ?c]
:where [[?e :co-ordinate ?c]
[(?pred ?c)]]
:in [$ ?pred]}
@conn
#(= 1 (:y %)))))
Though there are other ways to express it which are probably better... the point is just that the arguments to the predicate are not evaluated.=> #{[2 {:x 1, :y 1, :z 2}] [1 {:x 0, :y 1, :z 2}]}
The nicer way to express it would be:
'{:find [?e ?c]
:where [[?e :co-ordinate ?c]
[(get ?c :y) ?y]
[(= 1 ?y)]]}^^ This evaluates the y lookup separately and binds it to ?y which can be used with the predicate = directly. https://docs.datomic.com/on-prem/query/query.html#function-expressions
I guess I'll find a way to flatten the map into the entity instead
Yup well something like {:db/id 1, :x 0, :y 1, :z 2} isn't much different, and is easier to query 🙂
or you can make :co-ordinate a ref instead of a value, either will work.