Crux Mercury Assignment: Datalog Queries

Crux Mercury Assignment: Datalog Queries

July 22, 2019
Johanna Antonelli

earth pluto mercury neptune saturn jupiter comet planet a


This is the third installment of the Crux tutorial, focusing on Datalog queries.

We shall assume you have a Crux standalone node set up locally and are now comfortable with put operations. If this is not the case, you can find all you need to know on Earth and Pluto. Click on a destination above to take you there.

Arrival on Mercury

You come into range of the satellites orbiting Mecury. Your communications panel lights up and you read:


You have reached Mercury, home to the greatest stock market in the Solar System. Your ship has been flagged as a transport vessel for business related activities.

Please have your flight manifest ready and prepare to land.

— Mercury Commonwealth

The government is asking to see your flight manifest.

Choose your path:

You have your manifest You do not have your manifest

You have permission to land

These people look like they wouldn’t take kindly to time wasters. You return to Pluto and fill in your manifest.



Space Port

You read your Crux manual as you wait for an available landing pad.

A Datalog query consists of a set of variables and a set of clauses. The result of running a query is a result set (or lazy sequence) of the possible combinations of values that satisfy all of the clauses at the same time. These combinations of values are referred to as "tuples".

The possible values within the result tuples are derived from your database of documents. The documents themselves are represented in the database indexes as "entity–attribute–value" (EAV) facts. For example, a single document {:crux.db/id :myid :color "blue" :age 12} is transformed into two facts [[:myid :color "blue"][:myid :age 12]].

In the most basic case, a Datalog query works by searching for "subgraphs" in the database that match the pattern defined by the clauses. The values within these subgraphs are then returned according to the list of return variables requested in the :find vector within the query.

— Crux manual
Read More


You land on the surface of the tidally locked planet. As you do, the job ticket for this assignment is issued.


Find information on products for stock buyers


Interplanetary Buyers & Sellers (IPBS)


Cosmina Sinnett



Additional information

We have some new starters in the sales team. They need to be trained on how to query Crux using Datalog to quickly find the information they need on a product. Traders must have access to up-to-date information when talking to their clients. We would also like you to create a function that can be used for the things we have to look up a lot. I will include example data so they can learn using relevant commodities.



On your way over to the IPBS office you input the data in the attachment using the easy ingest function you created on Pluto. This means you are ready to give them a tutorial when you get there.

Oh good, you’re here.

I have a room reserved and we have five new starters ready and waiting to learn how to query Crux.

Did you manage to get the example data from the ticket I submitted?

— Cosmina Sinnett
Head of Training - IPBS

Choose your path

"Yes I’ve already got it in Crux ready to go." "No."
pluto surface


We are in the middle of our double sunrise. The workers take this time to rest, but in half an Earth hour the sun will rise again and the workers will start back.

You can take this time to prepare any training material if you wish.

— Cosmina Sinnett
Head of Training - IPBS

You have the opportunity to prepare examples for the lesson ahead.

Choose your path

You use the time wisely and plan examples. You decide to wing it and see how the tutorial goes.

Go to lesson plan.

You go and teach the new starters. They are not impressed with your lack of preparation. They learn next to nothing and you realize you made a mistake.

pluto surface

Datalog Tutorial

You put together examples and make notes so you can be confident in your lesson.

Lesson Plan

Example 1. Basic Query
(crux/q (crux/db node)
        '{:find [element]
          :where [[element :type :element/metal]]})
;;=> #{[:commodity/Pu] [:commodity/Au]}

This basic query is returning all the elements that are defined as :element/metal. The :find clause tells Crux what variables you want to return.

In this case we are returning the :crux.db/id due to our placement of element.

— Notes
Example 2. Quoting
 (crux/q (crux/db node)
         '{:find [element]
           :where [[element :type :element/metal]]})

 (crux/q (crux/db node)
         {:find '[element]
          :where '[[element :type :element/metal]]})

 (crux/q (crux/db node)
          {:find [element]
           :where [[element :type :element/metal]]})))
;;=> true

The vectors given to the clauses should be quoted. How you do it at this stage is arbitrary, but it becomes more important if you are using :args, which we will cover momentarily.

— Notes
Example 3. Return the name of metal elements
(crux/q (crux/db node)
        '{:find [name]
          :where [[e :type :element/metal]
                  [e :common-name name]]})
;;=> #{["Gold"] ["Plutonium"]}

To find all the names of the commodities that have a certain property, such as :type, you need to use a combination of clauses. Here we have bound the results of type :element/metal to e. Next, we can use the results bound to e and bind the :common-name of them to name. name is what has been specified to be returned and so our result is the common names of all the elements that are metals.

One way to think of this is that you are filtering to only get the results that satisfy all the clauses.

— Notes
Example 4. More information
(crux/q (crux/db node)
        '{:find [name rho]
          :where [[e :density rho]
                  [e :common-name name]]})
;;=> #{["Nitrogen" 1.2506] ["Carbon" 2.267] ["Methane" 0.717] ["Borax" 1.73] ["Gold" 19.3] ["Plutonium" 19.816]}

You can pull out as much data as you want into your result tuples by adding additional variables to the :find clause.

The example above returns the :density and the :common-name values for all entities in Crux that have values of some kind for both :density and :common-name attributes.

— Notes
Example 5. Arguments
(crux/q (crux/db node)
        {:find '[name]
         :where '[[e :type t]
                  [e :common-name name]]
         :args [{'t :element/metal}]})
;;=> #{["Gold"] ["Plutonium"]}

:args can be used to further filter the results. Lets break down what is going down here.

First, we are assigning all :crux.db/id that have a :type to e:

e#{[:commodity/Pu] [:commodity/borax] [:commodity/CH4] [:commodity/Au] [:commodity/C] [:commodity/N]}

At the same time we are assigning all the :types to t:

t#{[:element/gas] [:element/metal] [:element/non-metal] [:mineral/solid] [:molecule/gas]}

Then we assign all the names within e that have a :common-name to name:

name#{["Methane"] ["Carbon"] ["Gold"] ["Plutonium"] ["Nitrogen"] ["Borax"]}

We have specified that we want to get the names out, but not before looking at :args

In :args we have further filtered the results to only show us the names of that have :type :element/metal.

We could have done that inside the :where clause, but using :args removes the need for hard-coding inside the query clauses.

— Notes

You give your lesson to the new starters when they return. They are a good audience and follow it well.

To check their understanding you set them a task to create a function to aid their daily queries. You are impressed with their efforts.

(defn filter-type
  (crux/q (crux/db node)
        {:find '[name]
         :where '[[e :type t]
                  [e :common-name name]]
         :args [{'t type}]}))

(defn filter-appearance
  (crux/q (crux/db node)
        {:find '[name IUPAC]
         :where '[[e :common-name name]
                  [e :IUPAC-name IUPAC]
                  [e :appearance appearance]]
         :args [{'appearance description}]}))

(filter-type :element/metal)
;;=> #{["Gold"] ["Plutonium"]}

(filter-appearance "white solid")
;;=> #{["Borax" "Sodium tetraborate decahydrate"]}

When you are finished, Cosmina thanks you and you head back to the space port.

Space Port

You are back at your spaceship. Seeing another light on your communications panel, you realize there is another assignment ready for you.

Congratulations on completing your assignment. You are getting the hang of things now, and we are impressed with your progress.

We would like you to go to Neptune. They have recently lost a lot of data in a flood so they have decided to digitize their entire system and archives. We told them you could do it in such a way that the data is still time ordered as it was with their previous filing system.

Good luck, and don’t forget to update your manifest.

— Banking Inc.

You update your manifest with the latest badge.

 node [[:crux.tx/put (assoc manifest
                            :badges ["SETUP" "PUT" "DATALOG-QUERIES"])]])
;;=> #:crux.tx{:tx-id 1, :tx-time #inst "2020-06-18T14:31:46.148-00:00"}

Start countdown for lift off to Neptune. See you soon.

Click on Neptune to take you to your next assignment.