Read Revisited
First, don't forget to acquire the latest value of the database, after the transaction that added the order.
noslide
(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.
noslide
(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
Rules
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.