mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-18 21:12:09 +03:00
196 lines
4.7 KiB
ReStructuredText
196 lines
4.7 KiB
ReStructuredText
|
Modelling many-to-many table relationships
|
||
|
==========================================
|
||
|
|
||
|
A many-to-many relationship between two tables can be established by creating a table typically called as ``bridge``
|
||
|
or ``junction`` or ``join`` table and adding foreign-key constraints from it to the original tables.
|
||
|
|
||
|
Say we have the following two tables in our database schema:
|
||
|
|
||
|
.. code-block:: sql
|
||
|
|
||
|
article (
|
||
|
id INT PRIMARY KEY,
|
||
|
title TEXT
|
||
|
...
|
||
|
)
|
||
|
|
||
|
tag (
|
||
|
id INT PRIMARY KEY,
|
||
|
tag_value TEXT
|
||
|
...
|
||
|
)
|
||
|
|
||
|
These two tables are related via a ``many-to-many`` relationship. i.e:
|
||
|
|
||
|
- an ``article`` can have many ``tags``
|
||
|
- a ``tag`` has many ``articles``
|
||
|
|
||
|
This ``many-to-many`` relationship can be established in the database by:
|
||
|
|
||
|
1. Creating a bridge table called ``article_tag`` with the following structure:
|
||
|
|
||
|
.. code-block:: sql
|
||
|
|
||
|
article_tag (
|
||
|
id INT PRIMARY KEY
|
||
|
article_id INT
|
||
|
tag_id INT
|
||
|
...
|
||
|
)
|
||
|
|
||
|
2. Adding foreign-key constraints from the ``article_tag`` table to:
|
||
|
|
||
|
- the ``article`` table using the ``article_id`` and ``id`` columns of the tables respectively
|
||
|
- the ``tag`` table using the ``tag_id`` and ``id`` columns of the tables respectively
|
||
|
|
||
|
|
||
|
The table ``article_tag`` sits between the two tables involved in the many-to-many relationship and captures possible
|
||
|
permutations of their association via the foreign-keys.
|
||
|
|
||
|
To access the nested objects via the GraphQL API, :doc:`create the following relationships <../create>`:
|
||
|
|
||
|
- Array relationship, ``article_tags`` from ``article`` table using ``article_tag :: article_id -> id``
|
||
|
- Object relationship, ``tag`` from ``article_tag`` table using ``tag_id -> tag :: id``
|
||
|
- Array relationship, ``tag_articles`` from ``tag`` table using ``article_tag :: tag_id -> id``
|
||
|
- Object relationship, ``article`` from ``article_tag`` table using ``article_id -> article :: id``
|
||
|
|
||
|
|
||
|
We can now:
|
||
|
|
||
|
- fetch a list of articles with their tags:
|
||
|
|
||
|
.. graphiql::
|
||
|
:view_only:
|
||
|
:query:
|
||
|
query {
|
||
|
article {
|
||
|
id
|
||
|
title
|
||
|
article_tags {
|
||
|
tag {
|
||
|
id
|
||
|
tag_value
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
:response:
|
||
|
{
|
||
|
"data": {
|
||
|
"article": [
|
||
|
{
|
||
|
"id": 1,
|
||
|
"title": "sit amet",
|
||
|
"article_tags": [
|
||
|
{
|
||
|
"tag": {
|
||
|
"id": 1,
|
||
|
"tag_value": "mystery"
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
"tag": {
|
||
|
"id": 2,
|
||
|
"tag_value": "biography"
|
||
|
}
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"id": 2,
|
||
|
"title": "a nibh",
|
||
|
"article_tags": [
|
||
|
{
|
||
|
"tag": {
|
||
|
"id": 2,
|
||
|
"tag_value": "biography"
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
"tag": {
|
||
|
"id": 5,
|
||
|
"tag_value": "technology"
|
||
|
}
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- fetch a list of tags with their articles:
|
||
|
|
||
|
.. graphiql::
|
||
|
:view_only:
|
||
|
:query:
|
||
|
query {
|
||
|
tag {
|
||
|
id
|
||
|
tag_value
|
||
|
tag_articles {
|
||
|
article {
|
||
|
id
|
||
|
title
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
:response:
|
||
|
{
|
||
|
"data": {
|
||
|
"tag": [
|
||
|
{
|
||
|
"id": 1,
|
||
|
"tag_value": "mystery",
|
||
|
"tag_articles": [
|
||
|
{
|
||
|
"article": {
|
||
|
"id": 1,
|
||
|
"title": "sit amet"
|
||
|
}
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"id": 2,
|
||
|
"tag_value": "biography",
|
||
|
"tag_articles": [
|
||
|
{
|
||
|
"article": {
|
||
|
"id": 1,
|
||
|
"title": "sit amet"
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
"article": {
|
||
|
"id": 2,
|
||
|
"title": "a nibh"
|
||
|
}
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.. note::
|
||
|
|
||
|
The intermediate fields ``article_tags`` & ``tag_articles`` are important as they can be used to fetch extra
|
||
|
information about the relationship. For example, you can have a column like ``tagged_at`` in the ``article_tag``
|
||
|
table which you can fetch as follows:
|
||
|
|
||
|
.. code-block:: graphql
|
||
|
|
||
|
query {
|
||
|
article {
|
||
|
id
|
||
|
title
|
||
|
article_tags {
|
||
|
tagged_at
|
||
|
tag {
|
||
|
tag_value
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|