Fork me on GitHub
#datomic
<
2021-08-27
>
Jakub Holý (HolyJak)08:08:15

Hi! If I remember correctly, datalog has some way to traverse references in reverse, using _ in the attribute name, is that correct? I could not find where in the docs it is explained. I see it e.g. in the https://github.com/cognitect-labs/day-of-datomic-cloud/blob/385438c4d983d9855bf40d83eaabb618048a7cfc/tutorial/query_tour.clj#L75. And my experiment seems to prove my suspicion that using attribute names (even non-ref) starting with _ will lead to weird errors. Yet I do not see that mentioned https://docs.datomic.com/on-prem/schema/schema.html#required-schema-attributes?!

Jakub Holý (HolyJak)10:08:29

Thank you! It would be nice if the docs mentioned that attribute local names must not start with _ ...

Jakub Holý (HolyJak)08:08:31

Q2: I need to write a function that returns a query for a later execution. The challenge is that I need to hardcode the argument it gets - a set of IDs - into the query itself. In SQL I would do (fn [ids] (str "SELECT * FROM TableX WHERE id IN (" (s/join "," ids) ")")) So far I have

(defn by-ids [ids]
  '[:find (pull ?e [*])
    :where [?e :reference/$id ?id]
    :in    $ [?id ...]]) ; FIXME how to include the provided ids in the query?
I am sure it is trivial but I just know too little... Any help is much appreciated! Perhaps do [(#{ids} ?id)] and drop the input? <-- worked Update: As per @schmee suggestion, I ended up with [... :where '[?e :reference/$id ?id] [(ground ids) '[?id ...]]]

8
schmee09:08:57

I believe that the right way to do this is to use multiple inputs: https://docs.datomic.com/on-prem/query/query.html#multiple-inputs

Jakub Holý (HolyJak)10:08:59

Multiple inputs would work if I had the input available when I am executing the query (since it is d/q that takes the arguments) but that is not the case, I need to bind this input when I create the query (as data). I.e. my function takes the ids as an argument and must return a query.

Jakub Holý (HolyJak)10:08:52

Thank you! That indeed works, and I expect it is more performant than using a fn

Jakub Holý (HolyJak)10:08:05

I would not discover this without you!

schmee10:08:15

happy to help 😄

Jakub Holý (HolyJak)10:08:23

What is the right way to write the query "Give me the references that have the given component-id as either their source or target"? One way I guess is

[:find '?e :where ['?t :component/id component-id], '[?e ?attr ?t] '[(ground #{:reference/source :reference/target}) [?attr ...])]
another would be
[:find '?e :where '(or (and [?e :reference/source ?t] ['?t :component/$id component-id])
                       (and [?e :reference/target ?t] ['?t :component/$id component-id]))]
though I do not like the duplication in the latter 🙏

hden13:08:51

[:find ?e
 :in $ ?id
 :where
 [?c :component/id ?id]
 (or [?e :reference/attr ?c]
     [?c :reference/attr ?e])]
If you are looking for graph traversal, see: https://forum.datomic.com/t/how-to-do-graph-traversal-with-rules/132