datalog

coby 2021-03-25T16:52:01.033100Z

Hopefully this is the right place to ask this... I'm struggling with constraining a join across a one-to-many association:

(d/q '[:find (pull ?p [:post/slug
                         {:post/fields
                          [:field/key
                           :field/lang
                           :field/content]}])
         :in $ ?slug ?lang
         :where
         [?p :post/slug ?slug]
         [?p :post/fields ?field]
         [?field :field/lang ?lang]]
       db "child-page" :en)
This returns fields in all languages, not just :en, which is not what I want. I suspect this is because :post/fields is :db.cardinality/many and the join does not constrain them properly. Is this possible or do I need to filter fields after the fact?

Joe Lane 2021-03-25T16:59:40.035Z

You can perform a query + pull in that find clause. Try this:

(d/q '[:find ?slug (pull ?field 
                          [:field/key
                           :field/lang
                           :field/content])
         :in $ ?slug ?lang
         :where
         [?p :post/slug ?slug]
         [?p :post/fields ?field]
         [?field :field/lang ?lang]]
       db "child-page" :en)

Joe Lane 2021-03-25T16:59:47.035200Z

@ctamayo ^^

coby 2021-03-25T17:02:11.035900Z

That works! Thanks!

Joe Lane 2021-03-25T17:03:14.037Z

If you really want a map you could do:

(d/q '[:find ?slug ?key ?lang ?content 
         :in $ ?slug ?lang
         :keys post/slug field/key field/lang field/content
         :where
         [?p :post/slug ?slug]
         [?p :post/fields ?field]
         [?field :field/key ?key]
         [?field :field/lang ?lang]
         [?field :field/content ?content]
       db "child-page" :en)