docs/docs/schema/common-patterns/data-modeling/one-to-many.mdx
import GraphiQLIDE from '@site/src/components/GraphiQLIDE';
A one-to-many relationship between two tables can be established via a foreign key constraint.
Say we have the following two tables in our database schema:
authors (
id SERIAL PRIMARY KEY,
name TEXT
)
articles (
id SERIAL PRIMARY KEY,
author_id INT
title TEXT
...
)
These two tables are related via a one-to-many relationship. i.e:
author can have many articlesarticle has one authorThis one-to-many relationship can be established in the database by:
articles table to the authors table using the author_id and id
columns of the tables respectively.This will ensure that the value of author_id column in the articles table is present in the id column of the
authors table.
To access the nested objects via the GraphQL API, create the following relationships:
articles from authors table using articles :: author_id -> idauthor from articles table using author_id -> authors :: idWe can now:
authors with their articles:<GraphiQLIDE
query={query { authors { id name articles { id title } } }}
response={{ "data": { "authors": [ { "id": 1, "name": "Justin", "articles": [ { "id": 15, "title": "vel dapibus at" }, { "id": 16, "title": "sem duis aliquam" } ] }, { "id": 2, "name": "Beltran", "articles": [ { "id": 2, "title": "a nibh" }, { "id": 9, "title": "sit amet" } ] } ] } }}
/>
articles with their author:<GraphiQLIDE
query={query { articles { id title author { id name } } }}
response={{ "data": { "articles": [ { "id": 1, "title": "sit amet", "author": { "id": 4, "name": "Anjela" } }, { "id": 2, "title": "a nibh", "author": { "id": 2, "name": "Beltran" } } ] } }}
/>
We can now:
author with their articles where the author might already exist (assume unique name for author):<GraphiQLIDE
query={mutation UpsertAuthorWithArticles { insert_author(objects: { name: "Felix", articles: { data: [ { title: "Article 1", content: "Article 1 content" }, { title: "Article 2", content: "Article 2 content" } ] } }, on_conflict: { constraint: author_name_key, update_columns: [name] } ) { returning { name articles { title content } } } }}
response={{ "data": { "insert_author": { "returning": [ { "name": "Felix", "articles": [ { "title": "Article 1", "content": "Article 1 content" }, { "title": "Article 2", "content": "Article 2 content" } ] } ] } } }}
/>
articles with their author where the author might already exist (assume unique name for author):<GraphiQLIDE
query={mutation upsertArticleWithAuthors { insert_article(objects: [ { title: "Article 1", content: "Article 1 content", author: { data: { name: "Alice" }, on_conflict: { constraint: author_name_key, update_columns: [name] } } }, { title: "Article 2", content: "Article 2 content", author: { data: { name: "Alice" }, on_conflict: { constraint: author_name_key, update_columns: [name] } } } ]) { returning { title content author { name } } } }}
response={{ "data": { "insert_article": { "returning": [ { "title": "Article 1", "content": "Article 1 content", "author": { "name": "Alice" } }, { "title": "Article 2", "content": "Article 2 content", "author": { "name": "Alice" } } ] } } }}
/>
:::info Note
You can avoid the on_conflict clause if you will never have conflicts.
:::