datascript

craftybones 2022-08-21T18:18:40.400009Z

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

craftybones 2022-08-21T18:20:58.260059Z

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

timothypratley 2022-08-21T19:30:09.439769Z

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.

timothypratley 2022-08-21T19:30:38.924379Z

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

timothypratley 2022-08-21T19:36:02.566609Z

The nicer way to express it would be:

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

timothypratley 2022-08-21T19:36:37.249199Z

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

craftybones 2022-08-22T04:37:55.883519Z

Thanks @timothypratley

😄 1
craftybones 2022-08-22T04:38:38.722459Z

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

timothypratley 2022-08-22T04:40:31.291309Z

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

timothypratley 2022-08-22T04:41:20.415529Z

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