Filtering Databases

Datomic's filter allows you to limit your database to datoms that match an arbitrary predicate, prior to passing that database to a query or entity call.

For example, imagine that you want to exclude all values of an attribute entirely from consideration. The following code creates a filter that rejects all datoms about the attribute :user/passwordHash.

(def password-hash-id (d/entid plain-db :user/passwordHash))
(def password-hash-filter (fn [_ ^Datom datom] (not= password-hash-id (.a datom))))
(def filtered-db (d/filter (d/db conn) password-hash-filter))

example code in Clojure

Joining Multiple Versions of the Same Database

It is idiomatic to join filtered and unfiltered versions of the same database. One motivating case is performance: Since filtering is not free, it makes sense to filter only the parts of the query that need filtering. For example, the query below uses an unfiltered database to find entities, and then a filtered version of the same database to limit the attributes visible through the entity() call:

(d/q '[:find ?ent
       :in $plain $filtered ?email
       :where [$plain ?e :user/email ?email]
       [(datomic.api/entity $filtered ?e) ?ent]]
     plain-db filtered-db "jdoe@example.com")

example code in Clojure

Filtering on Transaction Attributes

Filters can do more than look at single datoms. They can also consider datoms in the context of the entire database. For example, imagine that you mark the transactions in your system with a :source/confidence field that indicates your confidence in the source, on a scale from 0 to 100. You could then filter the database as follows:

public static Database filterByConfidence(Database db, final long conf) {
    return db.filter(new Database.Predicate<datomic.Datom>() {
        public boolean apply(Database db, Datom datom) {
            Long confidence = (Long) db.entity(datom.tx()).get(":source/confidence");
            return (confidence != null) && (confidence > conf);
        }
    });
}

Queries using this filter can the focus on finding data of interest, without worrying about the cross-cutting concern of how trusted the data is. The query below finds only the stories whose titles were added by sources with a trust score higher than 90:

q("[:find ?title" +
  " :where [_ :story/title ?title]]", filterByConfidence(db, 90L));

sample code in Java

Have more questions? Submit a request

0 Comments

Please sign in to leave a comment.
Powered by Zendesk