For

2024.1.28

PrismaのSelf-relationsを使ったテーブル設計

概要

データベースであるデータとあるデータが親子関係にあることを示すために、データ自体を管理するテーブルとそのデータの親子関係を管理するテーブルという2つのテーブルによって管理できそうですが、今回は単一のテーブルによってレコードの親子関係を表現できる設計パターンを試してみました。
状況によってはアンチパターンとなりうるので、データベース上で表現したいことと設計パターンが最適かどうかは都度判断が必要になりそうです。

PrismaのSelf-relations

今回はPrismaを使ったプロジェクトにおいて、PrismaのSelf-relationsを使って単一テーブルでレコードの親子関係を表現します。

Prisma - Self-relations

今回は Item というmodelを作ってみます。(実際にこんな抽象的なmodelはなさそうですが)

prisma_____schema.prisma_____model Item {
  id           Int      @id @default(autoincrement())
  parentItemId Int?
  name         String
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt
  parentItem   Item?    @relation("ParentAndChildren", fields: [parentItemId], references: [id])
  item         Item[]   @relation("ParentAndChildren")
}


上記のようにItemというmodelを定義しました。
parentItemId にItemのidが入っていない場合は最上位のItemとなります。

また、findManyしてきたItem[]を以下のようにすることで親子関係がまとまります。

TypeScript_____organizeItems.ts_____export const organizeItems = (
  items: Item[],
  parentItemId: number | null = null,
): OrganizedItem[] => {
  return items
    .filter((v) => v.parentItemId === parentItemId)
    .map((item) => ({
      ...item,
      children: organizeItems(items, Number(item.id)),
    }));
};
const organizedItems = organizeItems(items ?? []);


まとめ

今回は個人開発しているアプリケーションでSelf-relationsが適していそうだったため使ってみました。
テーブルの設計パターンのひとつとして覚えておければと思います。