Read Revisited

First, don't forget to acquire the latest value of the database, after the transaction that added the order.


(def db (d/db conn))

Parameterized Query

Now let's try a more complex query. We would like to be able to suggest additional items to shoppers, so we need a query that, given any inventory item, finds all the other items that have ever appeared in the same order.

Such a query will have two parameters:

  • a database value
  • an inventory entity id

Parameters enter query via additional arguments to q, and they are named by a corresponding :in clause. The special $ name is a placeholder for the database value.


(d/q '[:find ?sku
       :in $ ?inv
       :where [?item :item/id ?inv]
              [?order :order/items ?item]
              [?order :order/items ?other-item]
              [?other-item :item/id ?other-inv]
              [?other-inv :inv/sku ?sku]]
     db [:inv/sku "SKU-25"])
=> [["SKU-25"] ["SKU-26"]]

Notice how variables are used to join:

  • ?inv is bound on input to the entity id for SKU-25, which
  • joins to every order ?item mentioning ?inv, which
  • joins to every ?order of that ?item, which
  • joins to every ?other-item in those orders, which
  • joins to every ?other-inv inventory entity, which
  • joins to all the skus ?sku


The "related items" feature is so nice that we would like to use it in a bunch of different queries. You can name query logic as a rule and reuse it in multiple queries.

Create a rule named ordered-together that binds two variables ?inv and ?other-inv if they have ever appeared in the same order:

(def rules
  '[[(ordered-together ?inv ?other-inv)
     [?item :item/id ?inv]
     [?order :order/items ?item]
     [?order :order/items ?other-item]
     [?other-item :item/id ?other-inv]]])

Now you can pass these rules to a query, using the special :in name %, and then refer to the rules by name:

(d/q '[:find ?sku
       :in $ % ?inv
       :where (ordered-together ?inv ?other-inv)
              [?other-inv :inv/sku ?sku]]
     db rules [:inv/sku "SKU-25"])
=> [["SKU-25"] ["SKU-26"]]

So far we have created an accumulated data. Now let's look at what happens when things change over time.