I might have just confused myself, but I thought I remembered this working differently in datomic. How to return all items in a db with an attribute not in a specific value passed as an argument?
(let [db (-> (ds/empty-db)
(ds/db-with [{:db/id 1 :item/state :active}
{:db/id 2 :item/state :inactive}]))]
;; works. returns [2]
(ds/q '[:find [?e ...]
:in $ [?state ...]
:where
[?e :item/state]
(not [?e :item/state ?state])]
db
[:active])
; doesn't work, returns [2 1]
(ds/q '[:find [?e ...]
:in $ [?state ...]
:where
[?e :item/state]
(not [?e :item/state ?state])]
db
[:active :inactive])
)No, Datomic works the same. I wonder why :)
@(d/transact conn
[{:db/id "1" :name "Ivan"}
{:db/id "2" :name "Oleg"}
{:db/id "3" :name "Petr"}])
(d/q '[:find ?e ?n
:in $ [?name ...]
:where
[?e :name ?n]
(not [?e :name ?name])]
(d/db conn)
["Ivan" "Oleg"])
; => #{[17592186045420 "Petr"] [17592186045419 "Oleg"] [17592186045418 "Ivan"]}I guess the answer is that it’s interpreted as “not A OR not B”, when it should be “not A AND not B”
Asked in #datomic https://clojurians.slack.com/archives/C03RZMDSH/p1734800206703189
Ah, yeah, thanks for checking that. And now that you mention it, it does seem like correct behavior https://docs.datomic.com/query/query-data-reference.html#collection-binding > A relation binding is fully general, binding multiple variables positionally to a relation (collection of tuples) passed in. This can be used to ask "or" questions involving variables in the relation binding.
Not really, becasue OR works:
(d/q '[:find ?e ?n
:where
[?e :name ?n]
(not
(or
[?e :name "Ivan"]
[?e :name "Oleg"]))]
(d/db conn))
; => #{[17592186045420 "Petr"]}As does this:
@(d/transact conn
[{:db/id "1" :exclude "Ivan"}
{:db/id "2" :exclude "Oleg"}])
(d/q '[:find ?e ?n
:where
[?e :name ?n]
(not-join [?e]
[_ :exclude ?name]
[?e :name ?name])]
(d/db conn))
; => #{[17592186045420 "Petr"]}So it only doesn’t work if it comes from collection binding
My first interpretation of that quoted line was "run the whole query for each variable passed and return the union of the results", but it's kind of unclear
Ok I think I have an explanation. Right now ?e and ?state are not connected in your query. So it’s not “find entities that have state”, it’s more like for each possible entity, for each possible state. [?e :item/state] gives you (:inactive 1) (:active 1) (:inactive 2) (:active 2) Then negation does connect them. In particular,
(not [?e :item/state ?state])
gives you
(:active 1) (:inactive 2)
If you subtract second from the first, you get
(:active 2) (:inactive 1)
In other words, change [?e :item/state] to [?e :item/state ?state] and you’ll get what you wantedThat all makes sense, and I think is the cause of the problem. Except that I wasn't able to get this working: > In other words, change [?e :item/state] to [?e :item/state ?state] and you’ll get what you wanted Or any of a few variations on that that I've tried (e.g. using a separate input var). Please don't spend any more time on it on my behalf though 🙂 I've since just done the filtering outside of a query and that works.