Search code examples
datomicdatalog

Datomic apply predicate to attribute with cardinality many


Say I have a Datomic entity with a many-valued attribute (of numbers, for instance). How would I return a list of entities whose value doesn't contain a specific number?

As an example,

{:db/id #db/id [:db.part/db]
:db/ident :strs
:db/valueType :db.type/string
:db/cardinality :db.cardinality/many
db.install/_attribute :db.part/db
}

And I want to find all of the entities whose list doesn't contain the number 1.

If I do something like:
[:find ?e :where 
[?e :strs ?v]
(not [(.contains ?v "b")])
]

But I have

e1 :strs ["a", "b", "c"]
e2 :strs ["a", "b"]
e3 :strs ["h", "i", "j"]

then all of the entities are returned because the queries are interpreted as "find the entities who have a member of strs that doesn't contain "b"", but I need

"find the entities e for which every member does not contain "b"".

Thanks!


Solution

  • Values that are :cardinality/many in datomic are still stored as individual values under the hood. So the facts for e1 in your db are:

    [[e1 :strs "a" tx]
     [e1 :strs "b" tx]
     [e1 :strs "c" tx]]
    

    You can leverage that in your query:

    '[:find ?e
      :where
      [?e :strs]
      (not [?e :strs "b"])]
    

    That will find all of the ?e whose :strs value is not "b" for all of the facts in the db.