API リクエストでのリレーション管理
コンテンツタイプ間のリレーション(データベース層ではエンティティ同士の接続)は、エンティティを相互に結びつけることです。
リレーションは 管理画面、REST API、Document Service API のリクエストで管理できます。
Content API では、リクエストボディにパラメータを渡してリレーションを接続・切断・設定できます。このペイロードは単一エントリのリレーションとマルチリレー ション(one-to-many、many-to-one、many-to-many、many-way)の両方で使えます。複数リンクを許すリレーションフィールドでは、API はリレーション ID の配列を想定し、レスポンスでも配列を返します。
| パラメータ名 | 説明 | 更新の種類 |
|---|---|---|
connect | 新しいエンティティを接続します。disconnect と併用できます。位置指定引数と組み合わせて、リレーションの順序を定義できます。 | 部分 |
disconnect | エンティティの接続を切ります。connect と併用できます。 | 部分 |
set | 指定した集合に置き換えます。set を使うと、他エンティティへの既存の接続はすべて上書きされます。connect や disconnect とは併用できません。 | 全体 |
マルチリレーションは REST API と GraphQL API の両方で管理できます。connect、disconnect、set はどちらの API でも利用できます。一方、Document Service API はリレーション操作を扱いません。
コンテンツタイプで Internationalization (i18n) が有効な場合、特定ロケール向けにリレーションを設定するためにロケールを渡せます。次は Document Service API の例です。
await strapi.documents('api::restaurant.restaurant').update({
documentId: 'a1b2c3d4e5f6g7h8i9j0klm',
locale: 'fr',
data: {
category: {
connect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv']
}
}
})
ロケールを省略すると既定ロケールが使われます。
connect
リクエストボディで connect を使うと部分更新として、指定したリレーションを接続します。
connect には省略形と詳細形があります。
| 構文の種類 | 構文の例 |
|---|---|
| 省略形 | connect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv'] |
| 詳細形 | connect: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }] |
詳細形では リレーションの並べ替え も指定できます。
connect は disconnect と併用 できます。
メディア属性への connect は公式にはサポートされていません。上級者向けにアップロードファイルの ID を指定して接続する方法はありますが、Strapi が推奨・保証するものではなく、下書きと公開で ID が食い違うなど簡単に壊れます。利用は自己責任で慎重に行ってください。
- 省略形の例
- 詳細形の例
次のリクエストは、documentId が a1b2c3d4e5f6g7h8i9j0klm の restaurant を更新します。categories 属性で、それぞれ documentId で示した 2 件のカテゴリに接続します。
PUT http://localhost:1337/api/restaurants/a1b2c3d4e5f6g7h8i9j0klm
{
data: {
categories: {
connect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv']
}
}
}
const fetch = require('node-fetch');
const response = await fetch(
'http://localhost:1337/api/restaurants/a1b2c3d4e5f6g7h8i9j0klm',
{
method: 'put',
body: {
data: {
categories: {
connect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv']
}
}
}
}
);
次のリクエストは、documentId が a1b2c3d4e5f6g7h8i9j0klm の restaurant を更新します。categories 属性で、それぞれ documentId で示した 2 件のカテゴリに接続します。
PUT http://localhost:1337/api/restaurants/a1b2c3d4e5f6g7h8i9j0klm
{
data: {
categories: {
connect: [
{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' },
{ documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }
]
}
}
}
const fetch = require('node-fetch');
const response = await fetch(
'http://localhost:1337/api/restaurants/a1b2c3d4e5f6g7h8i9j0klm',
{
method: 'put',
body: {
data: {
categories: {
connect: [
{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' },
{ documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }
]
}
}
}
}
);
リレーションの並べ替え
4.6.0This feature requires Strapi version 4.6.0 or later.connect の詳細形では、位置引数を渡してリレーションの順序を定義できます。
詳細形はオブジェクトの配列で、各オブジェクトに接続するエントリの documentId と、任意の position(接続位置)を含めます。
このドキュメントの構文は one-to-many、many-to-many、many-way に特に有用です。
one-to-one、many-to-one、one-way でも同様の構文は使えますが、最後のリレーションだけが使われるため、短い形式(例: { data: { category: 'a1b2c3d4e5f6g7h8i9j0klm' } })を使う方がよいです(REST API のドキュメント 参照)。
position には次の 4 種類のいずれかを渡します。
| パラメータ名と構文 | 説明 | 型 |
|---|---|---|
before: documentId | 指定した documentId の前に並べます。 | documentId(文字列) |
after: documentId | 指定した documentId の後に並べます。 | documentId(文字列) |
start: true | 既存のリレーション一覧の先頭に並べます。 | Boolean |
end: true | 既存のリレーション一覧の末尾に並べます。 | Boolean |
position は省略可能で、省略時は position: { end: true } と同じです。
connect は配列のため、記述した順に処理されます(下の組み合わせ例を参照)。
同じリレーションを複数回接続しないでください。API がバリデーションエラーを返します。
- 基本的な例
- 組み合わせの例
データベースに次のレコードがあるとします。
categories: [
{ documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }
{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }
]
次のリクエストは、documentId が a1b2c3d4e5f6g7h8i9j0klm の restaurant を更新し、categories に documentId が ma12bc34de56fg78hi90jkl のリレーションを追加し、documentId z0y2x4w6v8u1t3s5r7q9onm のエンティティの前に置きます。
PUT http://localhost:1337/api/restaurants/a1b2c3d4e5f6g7h8i9j0klm
{
data: {
categories: {
connect: [
{ documentId: 'ma12bc34de56fg78hi90jkl', position: { before: 'z0y2x4w6v8u1t3s5r7q9onm' } },
]
}
}
}
デー タベースに次のレコードがあるとします。
categories: [
{ documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }
{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }
]
PUT のボディに次の例を送ると、複数のリレーションをまとめて更新します。
PUT http://localhost:1337/api/restaurants/a1b2c3d4e5f6g7h8i9j0klm
{
data: {
categories: {
connect: [
{ id: '6u86wkc6x3parjd4emikhmx', position: { after: 'j9k8l7m6n5o4p3q2r1s0tuv'} },
{ id: '3r1wkvyjwv0b9b36s7hzpxl', position: { before: 'z0y2x4w6v8u1t3s5r7q9onm' } },
{ id: 'rkyqa499i84197l29sbmwzl', position: { end: true } },
{ id: 'srkvrr77k96o44d9v6ef1vu' },
{ id: 'nyk7047azdgbtjqhl7btuxw', position: { start: true } },
]
}
}
}
position を省略した要素(例: { id: 'srkvrr77k96o44d9v6ef1vu' })は、既定で position: { end: true } と同じ扱いです。他のリレーションは、既存の id を基準にした after / before、または一覧に対する start / end で相対的に配置されます。connect 配列の順に処理されるため、結果のデータベース上のレコードは次のようになります。
categories: [
{ id: 'nyk7047azdgbtjqhl7btuxw' },
{ id: 'j9k8l7m6n5o4p3q2r1s0tuv' },
{ id: '6u86wkc6x3parjd4emikhmx6' },
{ id: '3r1wkvyjwv0b9b36s7hzpxl7' },
{ id: 'a1b2c3d4e5f6g7h8i9j0klm' },
{ id: 'rkyqa499i84197l29sbmwzl' },
{ id: 'srkvrr77k96o44d9v6ef1vu9' }
]
エッジケース: 下書きと公開または i18n が無効な場合
コンテンツタイプで 下書きと公開 や Internationalization (i18n) がオフになっていると、connect の使い方が次のように変わることがあります。
i18n がオフの Category から、i18n がオンの Article へのリレーション:
接続先のロケールを次のように指定できます。
data: {
categories: {
connect: [
{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm', locale: 'en' },
// 同じ documentId で別ロケールに接続 👇
{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm', locale: 'fr' },
]
}
}
下書きと公開がオフの Category から、オンのアーティクルへのリレーション:
data: {
categories: {
connect: [
{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm', status: 'draft' },
// 同じ documentId で別の公開状態に接続 👇
{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm', status: 'published' },
]
}
}
disconnect
リクエストボディで disconnect を使うと部分更新として、指定したリレーションの接続を切ります。
disconnect にも省略形と詳細形があります。
| 構文の種類 | 構文の例 |
|---|---|
| 省略形 | disconnect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv'] |
| 詳細形 | disconnect: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }] |
disconnect は connect と併用できます。
- 省略形の例
- 詳細形の例
次のリクエストは、documentId が a1b2c3d4e5f6g7h8i9j0klm の restaurant を更新し、documentId で指定した 2 件のエントリとの接続を切ります。
PUT http://localhost:1337/api/restaurants/a1b2c3d4e5f6g7h8i9j0klm
{
data: {
categories: {
disconnect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv'],
}
}
}
次のリクエストは、documentId が a1b2c3d4e5f6g7h8i9j0klm の restaurant を更新し、documentId で指定した 2 件のエントリとの接続を切ります。
PUT http://localhost:1337/api/restaurants/a1b2c3d4e5f6g7h8i9j0klm
{
data: {
categories: {
disconnect: [
{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' },
{ documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }
],
}
}
}
set
set は全体更新で、既存のリレーションをすべて、指定した順序の集合に置き換えます。
set には省略形と詳細形があります。
| 構文の種類 | 構文の例 |
|---|---|
| 省略形 | set: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv'] |
| 詳細形 | set: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }] |
set は既存をすべて置き換えるため、他パラメータと併用しないでください。部分更新には connect と disconnect を使います。
set を省略する場合パラメータを省略するのは set を使うのと同じです。
例えば次の 3 つはいずれも同じ意味です。
data: { categories: set: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }] }}data: { categories: set: ['z0y2x4w6v8u1t3s5r7q9onm2', 'j9k8l7m6n5o4p3q2r1s0tuv'] }}data: { categories: ['z0y2x4w6v8u1t3s5r7q9onm2', 'j9k8l7m6n5o4p3q2r1s0tuv'] }
- 省略形の例
- 詳細形の例
次のリクエストは、documentId が a1b2c3d4e5f6g7h8i9j0klm の restaurant を更新し、以前のリレーションをす べて置き換えて、categories で documentId により指定した 2 件のカテゴリだけを接続します。
PUT http://localhost:1337/api/restaurants/a1b2c3d4e5f6g7h8i9j0klm
{
data: {
categories: {
set: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv4'],
}
}
}
次のリクエストは、documentId が a1b2c3d4e5f6g7h8i9j0klm の restaurant を更新し、以前のリレーションをすべて置き換えて、categories で documentId により指定した 2 件のカテゴリだけを接続します。
PUT http://localhost:1337/api/restaurants/a1b2c3d4e5f6g7h8i9j0klm
{
data: {
categories: {
set: [
{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' },
{ documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }
],
}
}
}