How to use input collection as an AND

My goal is to use :inputs as a collection input and then return all pages that have all tags. However, with my current query what it is doing is an OR instead of an AND. How can I change this logic?

#+BEGIN_QUERY
{
  :title [:h2 "Physical Devices"]
  :query [
    :find (pull ?p [*])
    :in $ [[?tag]]
    :where
      (page-tags ?p ?tag)
  ]
  :inputs [[[#{"device"}], [#{"homelab"}]]]
}
#+END_QUERY

Only way I can think of is separating everything out.

Think of the query as validating whether β€œany” is true.

So for this logic we have pages device and homelab.
Then we check if the page is tagged with any of the pages we put in.

The only way around that would be to change the input to separate values.
And then test those separate.

#+BEGIN_QUERY
{
  :title [:h2 "Physical Devices"]
  :query [
    :find (pull ?p [*])
    :in $ ?tag1 ?tag2
    :where
      (page-tags ?p ?tag1)
      (page-tags ?p ?tag2)
  ]
  :inputs [#{"device"} #{"homelab"}]
}
#+END_QUERY

If I understand your use case correctly, this may not be ideal. But it does work.

Yup, if I use both of them it works, but I wanted a way that could handle an arbitrary amount of tags.

In fact, as a concept, I wanted to understand if I could somehow make a query to which I can pass an arbitrary amount of parameters and make the query return something only if it conforms to all instead of any

Thanks a lot for the answer btw! I ended up using pretty much exactly the same you sent.

1 Like

Try double negation:

#+BEGIN_QUERY
{:title [:h2 "Physical Devices"]
 :query [
   :find (pull ?p [*])
   :in $ ?tag-names
   :where
     [?p :block/tags _]
     (not
          [?tag :block/name ?tag-name]
          [(contains? ?tag-names ?tag-name)]
          (not [?p :block/tags ?tag])
     )
 ]
 :inputs [#{"device" "homelab"}]
}
#+END_QUERY