メインコンテンツまでスキップ

Nested Write(update)

update メソッドの data 内でリレーション先のレコードを同時に操作できます。

create の Nested Write で使える操作に加えて、update / delete / deleteMany / disconnect / set 操作が利用できます。

複数のシートに書き込みますが、途中でエラーになった場合はどのシートにも 1 行も書かれません。詳細は書き込みの原子性と同時実行を参照してください。

説明例用のシート

リレーション定義のシート例を使用します。

使用できる操作

操作manyToOne / oneToOneoneToManymanyToMany
create単一のみ単一 / 配列単一 / 配列
createMany-対応-
connect対応単一 / 配列単一 / 配列
connectOrCreate対応単一 / 配列単一 / 配列
update対応単一 / 配列-
delete対応単一 / 配列-
deleteMany-単一 / 配列-
disconnect対応単一 / 配列単一 / 配列
set-対応対応
注記

manyToOne と oneToOne は使える操作の形は同じですが、動作が異なります。manyToOne(FK 保有側)は自レコードの FK を操作し、oneToOne(非FK側)は FK を保有するリレーション先レコードを操作します(リレーション定義を参照)。

oneToOne(非FK側)の挙動

操作動作対象レコードが存在しない場合
createリレーション先レコードを FK 自動セットで作成-
connect置き換え(既接続レコードの FK を null 化してから、対象レコードの FK を親にセット)NestedWriteConnectNotFoundError
connectOrCreate存在すれば connect と同じ置き換え、なければ FK 自動セットで作成-
updateリレーション先レコードを更新(data を直接指定)NestedWriteTargetNotFoundError
disconnect: trueリレーション先レコードの FK を null 化何もしない
delete: trueリレーション先レコードを削除NestedWriteTargetNotFoundError

set / deleteMany / createMany / 配列形式の指定は NestedWriteInvalidOperationError になります。

create

リレーション先のレコードを新規作成して関連付けます。create の Nested Write と同じ動作です。

// oneToMany: ユーザー更新時に新しい投稿を作成
gassma.Users.update({
where: { name: "Alice" },
data: {
posts: {
create: { id: 4, title: "新しい投稿", published: true },
},
},
});

connect

既存のリレーション先レコードを関連付けます。

// manyToOne: 投稿の著者を既存ユーザーに変更
gassma.Posts.update({
where: { id: 1 },
data: {
author: {
connect: { name: "Bob" },
},
},
});

oneToOne(非FK側)では置き換えとして動作します。すでに接続されているリレーション先レコードの FK を null にしてから、対象レコードの FK を親にセットします。

// oneToOne: ユーザーのプロフィールを別のプロフィールに置き換え
gassma.Users.update({
where: { name: "Alice" },
data: {
profile: {
connect: { id: 2 },
},
},
});
// => Profiles の id: 1(既接続)の userId が null になった後、
// id: 2 の userId が Alice の id(= 1)に更新される

connectOrCreate

既存のレコードがあれば関連付け、なければ新規作成して関連付けます。

// manyToOne: 著者が存在すれば接続、なければ作成
gassma.Posts.update({
where: { id: 1 },
data: {
author: {
connectOrCreate: {
where: { name: "Dave" },
create: { id: 4, name: "Dave", email: "[email protected]" },
},
},
},
});

update

関連するレコードを更新します。

manyToOne(FK 保有側)

更新データを直接指定します。自レコードの FK が参照しているレコードが更新されます。

// manyToOne: 投稿の著者名を更新
gassma.Posts.update({
where: { id: 1 },
data: {
author: {
update: { name: "Alice Updated" },
},
},
});

oneToOne(非FK側)

同じく更新データを直接指定します。親を参照しているリレーション先レコードが更新されます。

// oneToOne: ユーザーのプロフィールを更新
gassma.Users.update({
where: { name: "Alice" },
data: {
profile: {
update: { bio: "更新後の自己紹介" },
},
},
});
注意

接続されているリレーション先レコードが存在しない場合、NestedWriteTargetNotFoundError がスローされます。

oneToMany

wheredata を指定して更新対象を絞り込みます。配列で複数指定も可能です。

// oneToMany: 特定の投稿を更新
gassma.Users.update({
where: { name: "Alice" },
data: {
posts: {
update: {
where: { id: 1 },
data: { title: "更新後のタイトル" },
},
},
},
});

// 複数の投稿を同時に更新
gassma.Users.update({
where: { name: "Alice" },
data: {
posts: {
update: [
{ where: { id: 1 }, data: { title: "タイトルA" } },
{ where: { id: 2 }, data: { title: "タイトルB" } },
],
},
},
});

delete

関連するレコードを削除します。

manyToOne(FK 保有側)

delete: true を指定すると、関連先のレコードを削除し、自身の FK を null に設定します。

// manyToOne: 投稿の著者を削除(投稿の authorId は null になる)
gassma.Posts.update({
where: { id: 1 },
data: {
author: { delete: true },
},
});

oneToOne(非FK側)

delete: true を指定すると、親を参照しているリレーション先レコードを削除します。自レコードは変更されません。

// oneToOne: ユーザーのプロフィールを削除
gassma.Users.update({
where: { name: "Alice" },
data: {
profile: { delete: true },
},
});
// => Profiles の userId: 1 のレコードが削除される
注意

接続されているリレーション先レコードが存在しない場合、NestedWriteTargetNotFoundError がスローされます。

oneToMany

where 条件を指定して削除対象を絞り込みます。配列で複数指定も可能です。

// oneToMany: 特定の投稿を削除
gassma.Users.update({
where: { name: "Alice" },
data: {
posts: {
delete: { id: 3 },
},
},
});

// 複数削除
gassma.Users.update({
where: { name: "Alice" },
data: {
posts: {
delete: [{ id: 2 }, { id: 3 }],
},
},
});

deleteMany

条件に合致する関連レコードを一括削除します。oneToMany でのみ使用できます。

// oneToMany: 未公開の投稿を全て削除
gassma.Users.update({
where: { name: "Alice" },
data: {
posts: {
deleteMany: { published: false },
},
},
});

// 複数条件で削除
gassma.Users.update({
where: { name: "Alice" },
data: {
posts: {
deleteMany: [
{ published: false },
{ title: "下書き" },
],
},
},
});

disconnect

リレーションの関連付けを解除します。レコード自体は削除されません。

manyToOne(FK 保有側)

disconnect: true を指定すると、自身の FK を null に設定します。

// manyToOne: 投稿と著者の関連付けを解除
gassma.Posts.update({
where: { id: 1 },
data: {
author: { disconnect: true },
},
});
// => Posts の authorId が null になる

oneToOne(非FK側)

disconnect: true を指定すると、親を参照しているリレーション先レコードの FK を null に設定します。

// oneToOne: ユーザーとプロフィールの関連付けを解除
gassma.Users.update({
where: { name: "Alice" },
data: {
profile: { disconnect: true },
},
});
// => Profiles の userId: 1 が null になる

接続されているレコードが存在しない場合は何も行われません(エラーになりません)。

oneToMany

where 条件を指定して、関連レコードの FK を null に設定します。

// oneToMany: 特定の投稿の関連付けを解除
gassma.Users.update({
where: { name: "Alice" },
data: {
posts: {
disconnect: { id: 1 },
},
},
});
// => Posts の id: 1 の authorId が null になる

// 複数の関連付けを解除
gassma.Users.update({
where: { name: "Alice" },
data: {
posts: {
disconnect: [{ id: 1 }, { id: 2 }],
},
},
});

manyToMany

中間テーブルのレコードを削除します。

// manyToMany: タグの関連付けを解除
gassma.Posts.update({
where: { id: 1 },
data: {
tags: {
disconnect: { id: 3 },
},
},
});
// => PostTags テーブルから対応するレコードが削除される

set

リレーションの関連付けを全て入れ替えます。oneToMany と manyToMany でのみ使用できます。

oneToMany

全ての子レコードの FK を null に設定した後、指定したレコードの FK を親に設定します。

// oneToMany: Alice の投稿を id: 1 と id: 2 のみに置換
gassma.Users.update({
where: { name: "Alice" },
data: {
posts: {
set: [{ id: 1 }, { id: 2 }],
},
},
});
// => 既存の全投稿の authorId が null になった後、
// id: 1 と id: 2 の authorId が Alice の id に設定される

manyToMany

中間テーブルのレコードを全削除した後、指定したレコードとの関連を新規作成します。

// manyToMany: 投稿のタグを完全に入れ替え
gassma.Posts.update({
where: { id: 1 },
data: {
tags: {
set: [{ id: 10 }, { id: 11 }],
},
},
});
// => PostTags から投稿 id: 1 の全レコードが削除された後、
// 新しい関連レコードが作成される

複数操作の組み合わせ

1 つの update 内で複数のリレーション操作を組み合わせることも可能です。

gassma.Users.update({
where: { name: "Alice" },
data: {
name: "Alice Updated",
posts: {
create: { id: 5, title: "新記事", published: true },
update: { where: { id: 1 }, data: { title: "更新済み" } },
delete: { id: 3 },
},
},
});

エラー

エラー原因
NestedWriteWithoutRelationsErrorリレーション定義なしで Nested Write を実行した
NestedWriteInvalidOperationErrorリレーション種別に対応しない操作を指定した
NestedWriteConnectNotFoundErrorconnect / connectOrCreate で対象レコードが見つからなかった
NestedWriteTargetNotFoundError非FK側 oneToOne の update / delete でリレーション先レコードが存在しなかった