Lesson 3.1: Fetching simple data
The Fetch query
To begin with, we’ll use the following Fetch query to retrieve all data relating to paperback book entities in the database.
match
$book isa paperback;
fetch
$book: attribute;
Run
This is equivalent to the following SQL query.
SELECT *
FROM paperback;
This TypeQL query comprises two clauses: a match
clause and a fetch
clause.
The match
clause is equivalent to a selection in SQL. It identifies what entity types (tables) we wish to retrieve data from. It can also specify further constraints that the retrieved data must meet, as we’ll see shortly. The fetch
clause is equivalent to a projection in SQL. It specifies what attributes (columns) we would like to retrieve for the entities (rows) identified. In this case, we’ve chosen to retrieve all attributes using the attribute
keyword.
Using a data session and read transaction, run this query. You should see the following result.
{
"book": {
"attribute": [
{ "value": 1, "value_type": "long", "type": { "label": "stock", "root": "attribute" } },
{ "value": 240, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } },
{ "value": "9780393045215", "value_type": "string", "type": { "label": "isbn-13", "root": "attribute" } },
{ "value": 21.600000381469727, "value_type": "double", "type": { "label": "price", "root": "attribute" } },
{ "value": "history", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "nonfiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "0393045218", "value_type": "string", "type": { "label": "isbn-10", "root": "attribute" } },
{ "value": "The Mummies of Urumchi", "value_type": "string", "type": { "label": "title", "root": "attribute" } }
],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"attribute": [
{ "value": 12, "value_type": "long", "type": { "label": "stock", "root": "attribute" } },
{ "value": 820, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } },
{ "value": "9780195153446", "value_type": "string", "type": { "label": "isbn-13", "root": "attribute" } },
{ "value": 34.97999954223633, "value_type": "double", "type": { "label": "price", "root": "attribute" } },
{ "value": "history", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "nonfiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "0195153448", "value_type": "string", "type": { "label": "isbn-10", "root": "attribute" } },
{ "value": "Classical Mythology", "value_type": "string", "type": { "label": "title", "root": "attribute" } }
],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"attribute": [
{ "value": 16, "value_type": "long", "type": { "label": "stock", "root": "attribute" } },
{ "value": 281, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } },
{ "value": "9780446310789", "value_type": "string", "type": { "label": "isbn-13", "root": "attribute" } },
{ "value": 21.639999389648438, "value_type": "double", "type": { "label": "price", "root": "attribute" } },
{ "value": "fiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "historical fiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "0446310786", "value_type": "string", "type": { "label": "isbn-10", "root": "attribute" } },
{ "value": "To Kill a Mockingbird", "value_type": "string", "type": { "label": "title", "root": "attribute" } }
],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"attribute": [
{ "value": 8, "value_type": "long", "type": { "label": "stock", "root": "attribute" } },
{ "value": 260, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } },
{ "value": "9798691153570", "value_type": "string", "type": { "label": "isbn-13", "root": "attribute" } },
{ "value": 11.989999771118164, "value_type": "double", "type": { "label": "price", "root": "attribute" } },
{ "value": "business", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "nonfiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "Business Secrets of The Pharoahs", "value_type": "string", "type": { "label": "title", "root": "attribute" } }
],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"attribute": [
{ "value": 11, "value_type": "long", "type": { "label": "stock", "root": "attribute" } },
{ "value": 416, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } },
{ "value": "9780500026557", "value_type": "string", "type": { "label": "isbn-13", "root": "attribute" } },
{ "value": 24.469999313354492, "value_type": "double", "type": { "label": "price", "root": "attribute" } },
{ "value": "art", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "nonfiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "0500026556", "value_type": "string", "type": { "label": "isbn-10", "root": "attribute" } },
{ "value": "Hokusai's Fuji", "value_type": "string", "type": { "label": "title", "root": "attribute" } }
],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"attribute": [
{ "value": 15, "value_type": "long", "type": { "label": "stock", "root": "attribute" } },
{ "value": 295, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } },
{ "value": "9780553212150", "value_type": "string", "type": { "label": "isbn-13", "root": "attribute" } },
{ "value": 17.989999771118164, "value_type": "double", "type": { "label": "price", "root": "attribute" } },
{ "value": "fiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "historical fiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "055321215X", "value_type": "string", "type": { "label": "isbn-10", "root": "attribute" } },
{ "value": "Pride and Prejudice", "value_type": "string", "type": { "label": "title", "root": "attribute" } }
],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"attribute": [
{ "value": 15, "value_type": "long", "type": { "label": "stock", "root": "attribute" } },
{ "value": 199, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } },
{ "value": "9781489962287", "value_type": "string", "type": { "label": "isbn-13", "root": "attribute" } },
{ "value": 47.16999816894531, "value_type": "double", "type": { "label": "price", "root": "attribute" } },
{ "value": "nonfiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "technology", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "148996228X", "value_type": "string", "type": { "label": "isbn-10", "root": "attribute" } },
{ "value": "Interpretation of Electron Diffraction Patterns", "value_type": "string", "type": { "label": "title", "root": "attribute" } }
],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"attribute": [
{ "value": 4, "value_type": "long", "type": { "label": "stock", "root": "attribute" } },
{ "value": 160, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } },
{ "value": "9781859840665", "value_type": "string", "type": { "label": "isbn-13", "root": "attribute" } },
{ "value": 14.520000457763672, "value_type": "double", "type": { "label": "price", "root": "attribute" } },
{ "value": "biography", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "nonfiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "1859840663", "value_type": "string", "type": { "label": "isbn-10", "root": "attribute" } },
{ "value": "The Motorcycle Diaries: A Journey Around South America", "value_type": "string", "type": { "label": "title", "root": "attribute" } }
],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"attribute": [
{ "value": 18, "value_type": "long", "type": { "label": "stock", "root": "attribute" } },
{ "value": 352, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } },
{ "value": "9780500291221", "value_type": "string", "type": { "label": "isbn-13", "root": "attribute" } },
{ "value": 12.050000190734863, "value_type": "double", "type": { "label": "price", "root": "attribute" } },
{ "value": "history", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "nonfiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "0500291225", "value_type": "string", "type": { "label": "isbn-10", "root": "attribute" } },
{ "value": "Great Discoveries in Medicine", "value_type": "string", "type": { "label": "title", "root": "attribute" } }
],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"attribute": [
{ "value": 4, "value_type": "long", "type": { "label": "stock", "root": "attribute" } },
{ "value": 458, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } },
{ "value": "9780060929794", "value_type": "string", "type": { "label": "isbn-13", "root": "attribute" } },
{ "value": 6.119999885559082, "value_type": "double", "type": { "label": "price", "root": "attribute" } },
{ "value": "fiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "historical fiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "0060929790", "value_type": "string", "type": { "label": "isbn-10", "root": "attribute" } },
{ "value": "One Hundred Years of Solitude", "value_type": "string", "type": { "label": "title", "root": "attribute" } }
],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"attribute": [
{ "value": 9, "value_type": "long", "type": { "label": "stock", "root": "attribute" } },
{ "value": 215, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } },
{ "value": "9780671461492", "value_type": "string", "type": { "label": "isbn-13", "root": "attribute" } },
{ "value": 91.47000122070312, "value_type": "double", "type": { "label": "price", "root": "attribute" } },
{ "value": "fiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "science fiction", "value_type": "string", "type": { "label": "genre", "root": "attribute" } },
{ "value": "0671461494", "value_type": "string", "type": { "label": "isbn-10", "root": "attribute" } },
{ "value": "The Hitchhiker's Guide to the Galaxy", "value_type": "string", "type": { "label": "title", "root": "attribute" } }
],
"type": { "label": "paperback", "root": "entity" }
}
}
All Fetch queries return results in JSON format.
In the match
clause of the query, we declared a single variable: $book
. In TypeQL, variables are declared using a $
prefix. We also specified the type of $book
to be paperback
using the isa
keyword. We can see that each JSON object returned represents an instance of paperback
and contains a list of all that book’s attributes.
Write a query to retrieve all the attributes of user
entities. It should be equivalent to the following SQL query.
SELECT *
FROM users;
N.b. in the SQL query we need to use users
rather than user
as the latter is a reserved keyword in SQL. In general, singular nouns are preferred for entity type names.
Sample solution
match
$user isa user;
fetch
$user: attribute;
Run
Projections
Looking at the list of each book’s attributes in the previous result, we can see that we’ve retrieved attributes of six types: isbn-13
, isbn-10
, title
, genre
, page-count
, price
, and stock
. By modifying the fetch
clause, we can choose to retrieve only specific attributes.
match
$book isa paperback;
fetch
$book: title, page-count;
Run
If we run this query, we see the following result.
{
"book": {
"page-count": [ { "value": 352, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "Great Discoveries in Medicine", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"page-count": [ { "value": 416, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "Hokusai's Fuji", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"page-count": [ { "value": 199, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "Interpretation of Electron Diffraction Patterns", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"page-count": [ { "value": 295, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "Pride and Prejudice", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"page-count": [ { "value": 281, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "To Kill a Mockingbird", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"page-count": [ { "value": 260, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "Business Secrets of The Pharoahs", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"page-count": [ { "value": 240, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "The Mummies of Urumchi", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"page-count": [ { "value": 820, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "Classical Mythology", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"page-count": [ { "value": 458, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "One Hundred Years of Solitude", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"page-count": [ { "value": 215, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "The Hitchhiker's Guide to the Galaxy", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
{
"book": {
"page-count": [ { "value": 160, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "The Motorcycle Diaries: A Journey Around South America", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
This time, only the titles and page counts of each book have been retrieved. Now this TypeQL query is equivalent to the following SQL query.
SELECT title, page_count
FROM paperback;
Write a query to instead retrieve the isbn-13
, price
, and stock
attributes of paperbacks.
Sample solution
match
$book isa paperback;
fetch
$book: isbn-13, price, stock;
Run
Selections
In the next query, we’ll add a constraint to the match
clause, specifying that we want the details for a specific book with ISBN-13 "9780446310789"
.
match
$book isa paperback, has isbn-13 "9780446310789";
fetch
$book: title, page-count;
Run
{
"book": {
"page-count": [ { "value": 281, "value_type": "long", "type": { "label": "page-count", "root": "attribute" } } ],
"title": [ { "value": "To Kill a Mockingbird", "value_type": "string", "type": { "label": "title", "root": "attribute" } } ],
"type": { "label": "paperback", "root": "entity" }
}
}
We can see from the result that we now only retrieve the data for the specific book we’re interested in. To do so we’ve used the has
keyword, which is used to specify the value of an entity’s attribute, in this case the $book
entity. In SQL, this query would be expressed in the following way.
SELECT title, page_count
FROM paperback
WHERE isbn_13 = '9780446310789';
Because TypeQL is composable, we could alternatively construct this query in the following equivalent way.
match
$book isa paperback;
$book has isbn-13 "9780446310789";
fetch
$book: title, page-count;
Run
Try running these two queries. You should get the same results.
In the first version, we used a single composite statement in the match
clause, whereas in the second version, we instead used two simple statements. If simple statements concern the same variable (in this case $book
), we can always concatenate them using commas to form a composite statement, and vice versa.
Write a query to retrieve the page-count
and price
attributes of the paperback with title "Great Discoveries in Medicine"
. Write the query once using a composite statement, and again using simple statements.
Sample solution
With a composite statement:
match
$book isa paperback, has title "Great Discoveries in Medicine";
fetch
$book: page-count, price;
Run
With simple statements:
match
$book isa paperback;
$book has title "Great Discoveries in Medicine";
fetch
$book: page-count, price;
Run
Entities and relations
There are two types of data objects in TypeDB: entities and relations. Entity types like book
are used to represent application classes, while relation types are used to represent references between them. Relations must be instantiated with reference to one or more roleplayers, which play defined roles.
In order to represent a relation in TypeQL, we use tuple syntax of the following form.
$line (order: $order, item: $book) isa order-line;
This statement signifies that:
-
$line
is a relation of typeorder-line
. -
$order
plays the role oforder
in$line
. -
$book
plays the role ofitem
in$line
.
Here we are using order-line
relations to represent the references that order
entities make to book
entities. In the following Fetch query, we retrieve the IDs of orders that include To Kill a Mockingbird and the quantity ordered.
match
$book isa paperback, has isbn-13 "9780446310789";
$line (order: $order, item: $book) isa order-line;
fetch
$order: id;
$line: quantity;
Run
{
"line": {
"quantity": [ { "value": 1, "value_type": "long", "type": { "label": "quantity", "root": "attribute" } } ],
"type": { "label": "order-line", "root": "relation" }
},
"order": {
"id": [ { "value": "o0016", "value_type": "string", "type": { "label": "id", "root": "attribute" } } ],
"type": { "label": "order", "root": "entity" }
}
}
{
"line": {
"quantity": [ { "value": 1, "value_type": "long", "type": { "label": "quantity", "root": "attribute" } } ],
"type": { "label": "order-line", "root": "relation" }
},
"order": {
"id": [ { "value": "o0032", "value_type": "string", "type": { "label": "id", "root": "attribute" } } ],
"type": { "label": "order", "root": "entity" }
}
}
{
"line": {
"quantity": [ { "value": 2, "value_type": "long", "type": { "label": "quantity", "root": "attribute" } } ],
"type": { "label": "order-line", "root": "relation" }
},
"order": {
"id": [ { "value": "o0036", "value_type": "string", "type": { "label": "id", "root": "attribute" } } ],
"type": { "label": "order", "root": "entity" }
}
}
This is equivalent to the following SQL query.
SELECT orders.id, order_line.quantity
FROM orders
INNER JOIN order_line ON order_line.order_id = orders.id
INNER JOIN paperback ON paperback.isbn_13 = order_line.item_id
WHERE paperback.isbn_13 = '9780446310789';
In a relational database, the relation type order-line
would be represented by an associative table with foreign keys to the tables representing the entity types order
and paperback
1. As a general rule, associative tables in relational databases can be mapped onto relation types in TypeDB.
A key difference here is that the TypeQL query uses roles to connect the order-line
relation and its roleplayers $order
and $book
, whereas the SQL query connects different rows based on literal value equalities. Simply sharing a variable between multiple statements is sufficient to describe the connections between data instances in TypeQL, without having to identify attribute values to join on (like the order ID and book ISBN).
Modify the above query to also retrieve the status
attribute of the order and the price
attribute of the book.
Sample solution
match
$book isa paperback, has isbn-13 "9780446310789";
$line (order: $order, item: $book) isa order-line;
fetch
$order: id, status;
$line: quantity;
$book: price;
Run
Ternary relations
In the previous query, $line
was a binary relation between the two roleplayers $order
and $book
. However, the tuple syntax of relations is extremely flexible and allows us to use a tuple with a different number of elements to represent a relation with a different number of roleplayers. In the next query, we extend the previous query by also retrieving the name of the courier that is delivering the order and the street address of the order’s destination.
match
$book isa paperback, has isbn-13 "9780446310789";
$line (order: $order, item: $book) isa order-line;
(deliverer: $courier, delivered: $order, destination: $address) isa delivery;
fetch
$order: id;
$line: quantity;
$courier: name;
$address: street;
Run
{
"address": {
"street": [ { "value": "464 Pilgrim Lane", "value_type": "string", "type": { "label": "street", "root": "attribute" } } ],
"type": { "label": "address", "root": "entity" }
},
"courier": {
"name": [ { "value": "FedEx", "value_type": "string", "type": { "label": "name", "root": "attribute" } } ],
"type": { "label": "courier", "root": "entity" }
},
"line": {
"quantity": [ { "value": 1, "value_type": "long", "type": { "label": "quantity", "root": "attribute" } } ],
"type": { "label": "order-line", "root": "relation" }
},
"order": {
"id": [ { "value": "o0016", "value_type": "string", "type": { "label": "id", "root": "attribute" } } ],
"type": { "label": "order", "root": "entity" }
}
}
{
"address": {
"street": [ { "value": "984 Williams Street", "value_type": "string", "type": { "label": "street", "root": "attribute" } } ],
"type": { "label": "address", "root": "entity" }
},
"courier": {
"name": [ { "value": "FedEx", "value_type": "string", "type": { "label": "name", "root": "attribute" } } ],
"type": { "label": "courier", "root": "entity" }
},
"line": {
"quantity": [ { "value": 1, "value_type": "long", "type": { "label": "quantity", "root": "attribute" } } ],
"type": { "label": "order-line", "root": "relation" }
},
"order": {
"id": [ { "value": "o0032", "value_type": "string", "type": { "label": "id", "root": "attribute" } } ],
"type": { "label": "order", "root": "entity" }
}
}
{
"address": {
"street": [ { "value": "20 Ridge Lane", "value_type": "string", "type": { "label": "street", "root": "attribute" } } ],
"type": { "label": "address", "root": "entity" }
},
"courier": {
"name": [ { "value": "DHL", "value_type": "string", "type": { "label": "name", "root": "attribute" } } ],
"type": { "label": "courier", "root": "entity" }
},
"line": {
"quantity": [ { "value": 2, "value_type": "long", "type": { "label": "quantity", "root": "attribute" } } ],
"type": { "label": "order-line", "root": "relation" }
},
"order": {
"id": [ { "value": "o0036", "value_type": "string", "type": { "label": "id", "root": "attribute" } } ],
"type": { "label": "order", "root": "entity" }
}
}
Here the delivery is a ternary relation between three roleplayers: $courier
, $order
, and $address
. Higher order relations are used to represent rich references between multiple classes.
We have also not given the delivery a variable name. Compare this to the order line, which has the variable name $line
. In this case, the delivery relation is represented by an anonymous variable. In many cases where we do not need to refer to a relation anywhere else in the query, we can omit a variable name. As we need to refer to the order line in the fetch
clause to retrieve the associated quantity, we must give it the variable name $line
, but this is not the case for the delivery.
In a relational database, a ternary relation would be represented by an associative table between three foreign key columns. Write a SQL query that is equivalent to the above TypeQL query.
Sample solution
SELECT orders.id, order_line.quantity, courier.name, address.street
FROM orders
INNER JOIN order_line ON order_line.order_id = orders.id
INNER JOIN paperback ON paperback.isbn_13 = order_line.item_id
INNER JOIN delivery ON delivery.delivered_id = orders.id
INNER JOIN courier ON courier.id = delivery.courier_id
INNER JOIN address ON address.id = delivery.address_id
WHERE paperback.isbn_13 = '9780446310789';
In the same way that we can use a tuple with two or three elements respectively to represent a binary or ternary relation, we can likewise use a tuple with n elements for an n-ary relation!
This way, we can represent relations with any number of roleplayers. |
Footnotes
-
^ The seasoned SQL engineer will notice that, if paperbacks are not the only item that can be ordered, then we could not use a foreign key to reference them. We’d need a proper strategy for modeling the polymorphism in the model, likely one of Martin Fowler’s inheritance design patterns. If we go with the class-table inheritance pattern, then the foreign key would instead be to a
product
table. Conveniently, using this pattern means theisbn_13
column of thepaperback
table would reference theid
column of theproduct
table, so the SQL query shown would remain the same. As a polymorphic database, TypeDB is not affected by these architectural challenges! We’ll see how polymorphism is modeled in TypeDB in Lesson 5.