Advent of TypeQL: Day 4

A Christmassy data recovery adventure!

Joshua Send


Happy Advent!

Welcome to our Advent of TypeQL. Each day, we’ll post a small series of TypeQL challenges. There will be 14 days from December 11 to December 24, inclusive, so stay tuned!

It’ll be easiest to work through the days consecutively, since they are designed to incrementally build up an intuition of TypeQL. However, each day will also have a shortcut setup to just get a database for that day’s activity, allowing you to hop in without going through all the previous days challenges if you want.

You’ll want to use TypeDB Studio or TypeDB Console running against a TypeDB Cloud or local instance of TypeDB CE.

Background

Santa was preparing to release his Christmas plans. Finally done, he had just torn down his development and staging environments in preparation for a production launch of his grand Christmas plans…

Unfortunately at that precise moment, all of his Christmas plans, supposedly safely stashed in his git repository, got deleted by a pesky engineer with an overly permissive Github token and a mistyped command. Oh dear!

Santa contacted support and was able to recover some of his plans. However, they are incomplete. We’re going to help Santa get his plans back on track for Christmas, one day at a time!

Setup

If you’ve done Day 3, you can continue without setting anything up – just open up Studio or Console and get going!

If you’re new here, you’ll first want to spin up a TypeDB instance and connect with Studio or Console, and create a new database.

Then, you can get Santa’s recovered database schema by copying the linked schema text into a schema transaction’s query interface in Studio or Console, and the commit (note: by default, Studio auto-commits each query when set to “auto” mode).

Get the initial dataset plus subsequent days’ changes as a data file. Then load it by doing the same (follow link, copy text, paste into Studio or Console), but this time use a write transaction – and make sure you have committed.

At this point, you should have a database ready to go!

Day 4

Over the next 2 days, we’ll start ensuring the right elves are assigned to create presents for each continent’s kids.

Production type

Our overall goal is to create production relations. Let’s explore the schema to see what roles production relations relate, and what other types can play those roles.

Answer
match
  $t label production;
  $t relates $role;
  $player plays $role;
Hint

And let’s also have a quick look at what attributes productions can have.

Answer
match
  $t label production;
 $t owns $attribute;


It looks like we use productions to connect elf and present-blueprint instances, and we also need to indicate how many presents are required, which is the tricky part!

Computing quantities


Santa wants each working elf to create an equal number of each type of present, such that there are enough presents to cover all the kids in the continent where the elf lives.

So we’ll work out:

  1. Work out how many present types there are
  2. Work out how many kids live in each continent
  3. Divide number of kids by number of present types to get the number of each type of present

We can build this query incrementally and simply by taking advantage of TypeQL’s incredibly composable nature.

1. Number of present types

First, let’s count up how many present blueprints there are (same as Day 2 – use reduce).

Answer
match 
  $blueprint isa present-blueprint;
reduce $count = count;
Hint

https://typedb.com/docs/typeql-reference/pipelines/reduce/

There should be 10!

2. Number of kids in each continent

Next, we’ll need to sum up the number of kids in each continent.

We’ll definitely use a match to look up continents, and countries contained within (location-contains). Let’s start by counting the number of countries in each continent. We’ll need a groupby reduction!

Answer
match
  $continent isa continent;
  $country isa country;
  location-contains ($continent, $country);
reduce $count = count groupby $continent;
Hint

https://typedb.com/docs/typeql-reference/pipelines/reduce/#_grouping

We can now also work out the number of kids for a particular country using the population statistics – we did this before on day 2, using:

match
  $country isa country;
  demographics ($country, $stats);
  $stats isa country-statistics, has population $pop, has proportion-under-12 $under-12;
  let $kids = round($pop * $under-12);

Now the magic: we can simply merge the two match clauses together (make sure you align the country instances variable!), and switch the count to a sum, to achieve our goal of counting the number of kids per continent. Give it a shot!

Answer
match
  $continent isa continent;
  $country isa country;
  location-contains ($continent, $country);
  demographics ($country, $stats);
  $stats isa country-statistics, has population $pop, has proportion-under-12 $under-12;
  let $kids = round($pop * $under-12);
reduce $total-kids = sum($kids) groupby $continent;

We now have the number of kids per continent, exactly as we wanted.

3. Number of each type of present in each continent


We can now use another method for composing TypeQL queries, to combine the previous two results. To do this, we can just stack query clauses – first the blueprint count query, then the kids-per-continent query.

Answers will “flow” from one clause into the next and be available to be used for further operations until removed.

Try it and see!

Answer
match 
  $blueprint isa present-blueprint;
reduce $count = count;
match
  $continent isa continent;
  $country isa country;
  location-contains ($continent, $country);
  demographics ($country, $stats);
  $stats isa country-statistics, has population $pop, has proportion-under-12 $under-12;
  let $kids = round($pop * $under-12);
reduce $total-kids = sum($kids) groupby $continent;

Chances are that you’ll only get the same kids-per-continent answer as before.

That’s because the reduce only outputs variables that are computed or grouped on – it removes all other variables. To fix this, you extend the groupby to include the blueprint count variable. Then, we’ll get everything we need to compute the number of presents of each type, per continent.

Answer
match 
  $blueprint isa present-blueprint;
reduce $count = count;
match
  $continent isa continent;
  $country isa country;
  location-contains ($continent, $country);
  demographics ($country, $stats);
  $stats isa country-statistics, has population $pop, has proportion-under-12 $under-12;
  let $kids = round($pop * $under-12);
reduce $total-kids = sum($kids) groupby $continent, $count;

Now we just have to do the division of number of kids by number of present types! Math and expression evaluation is allowed in match clauses, so let’s just append another one at the end that does the computation.

Answer
match 
  $blueprint isa present-blueprint;
reduce $count = count;
match
  $continent isa continent;
  $country isa country;
  location-contains ($continent, $country);
  demographics ($country, $stats);
  $stats isa country-statistics, has population $pop, has proportion-under-12 $under-12;
  let $kids = round($pop * $under-12);
reduce $total-kids = sum($kids) groupby $continent, $count;
match 
  let $each-present-count = round($total-kids / $count);


In TypeQL, we call these stacks of clauses query pipelines. In fact, even a simple query containing only a single match clause is a tiny query pipeline, but their power really comes out in composing multiple clauses into longer pipelines.

In any TypeQL queries, answers to variables “flow” from one clause to the next, and allow you to compose any sequence in any order. Any mismatches are flagged during type checking.

See you soon!

We’ve made more progress rebuilding Santa’s data – great job! We’ll continue our work by writing the actual production relations tomorrow – Day 5. Now available here!

If you encounter any issues, want to chat, or anything else – feel free to post in our Discord or feel free to email me directly.

Share this article

TypeDB Newsletter

Stay up to date with the latest TypeDB announcements and events.

Subscribe to newsletter

Further Learning

Feedback