Fork me on GitHub
#datascript
<
2022-08-21
>
craftybones18:08:40

[{: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?

craftybones18:08:58

[:find ?e
 :where [?e :co-ordinate ?x] [(= 1 (:y ?x))]]
doesn't work, obviously

timothypratley19:08:09

The 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.

timothypratley19:08:38

=> #{[2 {:x 1, :y 1, :z 2}] [1 {:x 0, :y 1, :z 2}]}

timothypratley19:08:02

The nicer way to express it would be:

'{:find [?e ?c]
  :where [[?e :co-ordinate ?c]
          [(get ?c :y) ?y]
          [(= 1 ?y)]]}

timothypratley19:08:37

^^ 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

craftybones04:08:38

I guess I'll find a way to flatten the map into the entity instead

timothypratley04:08:31

Yup well something like {:db/id 1, :x 0, :y 1, :z 2} isn't much different, and is easier to query 🙂

timothypratley04:08:20

or you can make :co-ordinate a ref instead of a value, either will work.