メインコンテンツにスキップ

モデル

Prismaスキーマのデータモデル定義部分では、アプリケーションモデル(Prismaモデルとも呼ばれます)を定義します。モデル

  • アプリケーションドメインのエンティティを表します
  • データベース内のテーブル(PostgreSQLなどのリレーショナルデータベース)またはコレクション(MongoDB)にマッピングします
  • 生成されたPrisma Client APIで利用可能なクエリの基盤を形成します
  • TypeScriptで使用すると、Prisma Clientは、モデルと、データベースアクセスを完全に型安全にするためのモデルのバリエーションの生成された型定義を提供します。

次のスキーマは、ブログプラットフォームについて説明しています - データモデル定義が強調表示されています

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

generator client {
provider = "prisma-client-js"
}

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}

model Profile {
id Int @id @default(autoincrement())
bio String
user User @relation(fields: [userId], references: [id])
userId Int @unique
}

model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
categories Category[]
}

model Category {
id Int @id @default(autoincrement())
name String
posts Post[]
}

enum Role {
USER
ADMIN
}

データモデル定義は、以下で構成されています

対応するデータベースは次のようになります

Sample database

モデルは、データソースの基盤となる構造にマッピングされます。
  • PostgreSQLやMySQLなどのリレーショナルデータベースでは、modelテーブルにマッピングされます
  • MongoDBでは、modelコレクションにマッピングされます

:将来的には、非リレーショナルデータベースやその他のデータソース用のコネクタが存在する可能性があります。たとえば、REST APIの場合、リソースにマッピングされます。

次のクエリは、このデータモデルから生成されたPrisma Clientを使用して作成します

  • Userレコード
  • 2つのネストされたPostレコード
  • 3つのネストされたCategoryレコード
const user = await prisma.user.create({
data: {
email: 'ariadne@prisma.io',
name: 'Ariadne',
posts: {
create: [
{
title: 'My first day at Prisma',
categories: {
create: {
name: 'Office',
},
},
},
{
title: 'How to connect to a SQLite database',
categories: {
create: [{ name: 'Databases' }, { name: 'Tutorials' }],
},
},
],
},
},
})

データモデルは、あなたのアプリケーションドメインを反映しています。例:

  • eコマースアプリケーションでは、CustomerOrderItemInvoiceのようなモデルがあるでしょう。
  • ソーシャルメディアアプリケーションでは、UserPostPhotoMessageのようなモデルがあるでしょう。

イントロスペクションとマイグレーション

データモデルを定義するには、2つの方法があります

  • データモデルを手動で記述し、Prisma Migrateを使用する:データモデルを手動で記述し、Prisma Migrateを使用してデータベースにマッピングできます。この場合、データモデルはアプリケーションのモデルの単一の信頼できる情報源です。
  • イントロスペクションを介してデータモデルを生成する:既存のデータベースがある場合、またはSQLでデータベーススキーマを移行することを好む場合は、データベースをイントロスペクトしてデータモデルを生成します。この場合、データベーススキーマはアプリケーションのモデルの単一の信頼できる情報源です。

モデルの定義

モデルは、アプリケーションドメインのエンティティを表します。モデルはmodelブロックで表され、多数のフィールドを定義します。上記のデータモデル例では、UserProfilePostCategoryがモデルです。

ブログプラットフォームは、次のモデルで拡張できます

model Comment {
// Fields
}

model Tag {
// Fields
}

モデル名をテーブルまたはコレクションにマッピングする

Prismaモデルの命名規則(単数形、パスカルケース)は、データベースのテーブル名と常に一致するとは限りません。データベースでテーブル/コレクションに名前を付ける一般的なアプローチは、複数形とsnake_case表記を使用することです。例:commentscommentsという名前のテーブルを持つデータベースをイントロスペクトすると、結果のPrismaモデルは次のようになります

model comments {
// Fields
}

ただし、@@map属性を使用することで、基盤となるデータベースのcommentsテーブルの名前を変更せずに、命名規則に準拠できます

model Comment {
// Fields

@@map("comments")
}

このモデル定義により、Prisma ORMはCommentモデルを基盤となるデータベースのcommentsテーブルに自動的にマッピングします。

:カラム名またはEnum値を@mapすることも、Enum名を@@mapすることもできます。

@map@@mapを使用すると、基盤となるデータベースのテーブル名とカラム名からモデル名とフィールド名を切り離すことで、Prisma Client APIの形状を調整できます。

フィールドの定義

モデルのプロパティはフィールドと呼ばれ、以下で構成されています

フィールドの型は、その構造を決定し、次の2つのカテゴリのいずれかに分類されます

  • スカラー型Enumを含む)は、データベース内のカラム(リレーショナルデータベース)またはドキュメントフィールド(MongoDB)にマッピングされます。たとえば、StringまたはIntなどです
  • モデル型(フィールドはリレーションフィールドと呼ばれます) - たとえば、PostまたはComment[]

次の表は、サンプルスキーマのUserモデルのフィールドについて説明しています

テーブルを表示するには展開
名前スカラー vs リレーション型修飾子属性
idIntスカラー-@id および @default(autoincrement())
emailStringスカラー-@unique
nameStringスカラー?-
roleRoleスカラー(enum-@default(USER)
postsPostリレーション(Prismaレベルのフィールド)[]-
profileProfileリレーション(Prismaレベルのフィールド)?-

スカラーフィールド

次の例は、いくつかのスカラー型でCommentモデルとTagモデルを拡張しています。一部のフィールドには属性が含まれています

model Comment {
id Int @id @default(autoincrement())
title String
content String
}

model Tag {
name String @id
}

スカラーフィールド型の完全なリストを参照してください。

リレーションフィールド

リレーションフィールドの型は別のモデルです。たとえば、投稿(Post)には複数のコメント(Comment[])を含めることができます

model Post {
id Int @id @default(autoincrement())
// Other fields
comments Comment[] // A post can have many comments
}

model Comment {
id Int
// Other fields
post Post? @relation(fields: [postId], references: [id]) // A comment can have one post
postId Int?
}

モデル間のリレーションシップの詳細と例については、リレーションのドキュメントを参照してください。

ネイティブ型のマッピング

バージョン2.17.0以降では、基盤となるデータベース型を記述するネイティブデータベース型属性(型属性)をサポートしています

model Post {
id Int @id
title String @db.VarChar(200)
content String
}

型属性は

  • 基盤となるプロバイダーに固有です。たとえば、PostgreSQLはBoolean@db.Booleanを使用し、MySQLは@db.TinyInt(1)を使用します
  • パスカルケースで記述されています(例:VarCharまたはText
  • @dbがプレフィックスとして付加されています。dbはスキーマのdatasourceブロックの名前です

さらに、イントロスペクション中、基盤となるネイティブ型がデフォルト型ではない場合にのみ、型属性がスキーマに追加されます。たとえば、PostgreSQLプロバイダーを使用している場合、基盤となるネイティブ型がtextであるStringフィールドには型属性がありません。

スカラー型およびプロバイダーごとのネイティブデータベース型属性の完全なリストを参照してください。

利点とワークフロー

  • Prisma Migrateがデータベースに作成する正確なネイティブ型を制御します。たとえば、String@db.VarChar(200)または@db.Char(50)にできます
  • イントロスペクトするときにリッチスキーマを表示します

型修飾子

フィールドの型は、次の2つの修飾子のいずれかを追加することで変更できます

  • [] フィールドをリストにする
  • ? フィールドをオプションにする

:型修飾子を組み合わせることはできません。オプションのリストはサポートされていません。

リスト

次の例には、スカラーリストと関連モデルのリストが含まれています

model Post {
id Int @id @default(autoincrement())
// Other fields
comments Comment[] // A list of comments
keywords String[] // A scalar list
}

:スカラーリストは、データベースコネクタがスカラーリストをネイティブまたはPrisma ORMレベルでサポートしている場合にのみサポートされます。

オプションフィールドと必須フィールド

model Comment {
id Int @id @default(autoincrement())
title String
content String?
}

model Tag {
name String @id
}

フィールドに?型修飾子を注釈を付けない場合、フィールドはモデルのすべてのレコードで必須になります。これには2つのレベルで影響があります

  • データベース
    • リレーショナルデータベース:必須フィールドは、基盤となるデータベースのNOT NULL制約を介して表されます。
    • MongoDB:必須フィールドは、MongoDBデータベースレベルの概念ではありません。
  • Prisma Client:Prisma Clientの生成されたTypeScript型は、アプリケーションコードのモデルを表し、これらのフィールドを必須として定義して、ランタイム時に常に値を保持するようにします。

:オプションフィールドのデフォルト値はnullです。

サポートされていない型

リレーショナルデータベースをイントロスペクトすると、サポートされていないデータ型がUnsupportedとして追加されます

location    Unsupported("POLYGON")?

Unsupported型を使用すると、Prisma ORMでまだサポートされていないデータベース型のフィールドをPrismaスキーマで定義できます。たとえば、MySQLのPOLYGON型は現在Prisma ORMでサポートされていませんが、Unsupported("POLYGON")型を使用してPrismaスキーマに追加できるようになりました。

Unsupported型のフィールドは、生成されたPrisma Client APIには表示されませんが、Prisma ORMの生のデータベースアクセス機能を使用してこれらのフィールドをクエリすることはできます。

:モデルに必須のUnsupportedフィールドがある場合、生成されたクライアントにはそのモデルのcreateメソッドまたはupdateメソッドは含まれません。

:MongoDBコネクタは、すべてのスカラー型をサポートしているため、Unsupported型をサポートも必要としません。

属性の定義

属性は、フィールドまたはモデルブロックの動作を変更します。次の例には、3つのフィールド属性(@id@default、および@unique)と1つのブロック属性(@@unique)が含まれています

model User {
id Int @id @default(autoincrement())
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)

@@unique([firstName, lastName])
}

一部の属性は引数を受け入れます。たとえば、@defaulttrueまたはfalseを受け入れます

isAdmin   Boolean @default(false) // short form of @default(value: false)

フィールド属性とブロック属性の完全なリストを参照してください

IDフィールドの定義

IDは、モデルの個々のレコードを一意に識別します。モデルには1つのIDのみを含めることができます

  • リレーショナルデータベースでは、IDは単一のフィールドまたは複数のフィールドに基づいて作成できます。モデルに@idまたは@@idがない場合は、代わりに必須の@uniqueフィールドまたは@@uniqueブロックを定義する必要があります。
  • MongoDBでは、IDは@id属性と@map("_id")属性を定義する単一のフィールドである必要があります。

リレーショナルデータベースでのIDの定義

リレーショナルデータベースでは、IDは@id属性を使用した単一のフィールド、または@@id属性を使用した複数のフィールドで定義できます。

単一フィールドID

次の例では、User IDはid整数フィールドで表されます

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
複合ID

次の例では、User IDはfirstNameフィールドとlastNameフィールドの組み合わせで表されます

model User {
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)

@@id([firstName, lastName])
}

デフォルトでは、Prisma Clientクエリでのこのフィールドの名前はfirstName_lastNameになります。

@@id属性のnameフィールドを使用して、複合IDの独自の名前を提供することもできます

model User {
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)

@@id(name: "fullName", fields: [firstName, lastName])
}

firstName_lastNameフィールドの名前がfullNameに変更されました。

情報

Prisma Clientで複合IDを操作する方法については、複合IDの操作に関するドキュメントを参照してください。

一意の識別子としての@uniqueフィールド

次の例では、ユーザーは@uniqueフィールドによって一意に識別されます。emailフィールドはモデルの一意の識別子として機能するため(必須)、必須である必要があります

model User {
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
情報

リレーショナルデータベースの制約名
カスタムプライマリキー制約名を基盤となるデータベースでオプションで定義できます。

MongoDBでのIDの定義

MongoDBコネクタには、リレーショナルデータベースとは異なるIDフィールドを定義するための特定ルールがあります。IDは、@id属性を使用した単一のフィールドで定義する必要があり、@map("_id")を含める必要があります。

次の例では、User IDは自動生成されたObjectIdを受け入れるid文字列フィールドで表されます

model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}

次の例では、User IDはObjectId以外のもの(たとえば、一意のユーザー名)を受け入れるid文字列フィールドで表されます

model User {
id String @id @map("_id")
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
警告

MongoDBは@@idをサポートしていません
MongoDBは複合IDをサポートしていないため、@@idブロックでモデルを識別することはできません。

デフォルト値の定義

@default属性を使用して、モデルのスカラーフィールドのデフォルト値を定義できます

model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String
published Boolean @default(false)
data Json @default("{ \"hello\": \"world\" }")
author User @relation(fields: [authorId], references: [id])
authorId Int
categories Category[] @relation(references: [id])
}

@default属性は、次のいずれかです

  • 基盤となるデータベースのDEFAULT値を表します(リレーショナルデータベースのみ)または
  • Prisma ORMレベルの関数を使用します。たとえば、cuid()uuid()は、すべてのコネクタに対してPrisma Clientのクエリエンジンによって提供されます。

デフォルト値は次のいずれかになります

  • 5Int)、HelloString)、falseBoolean)など、フィールド型に対応する静的な値
  • [5, 6, 8]Int[])または["Hello", "Goodbye"]String[])などの静的な値のリスト。これらは、サポートされているデータベース(PostgreSQL、CockroachDB、MongoDB)を使用する場合、Prisma ORMバージョン4.0.0以降で利用できます
  • 関数now()uuid()など)
  • JSONデータ。JSONは@default属性内で二重引用符で囲む必要があることに注意してください。例:@default("[]")。JSONオブジェクトを提供する場合は、二重引用符で囲み、内部の二重引用符をバックスラッシュを使用してエスケープする必要があります。例:@default("{ \"hello\": \"world\" }")
情報

関数のコネクタサポートに関する情報については、属性関数リファレンスドキュメントを参照してください。

一意のフィールドの定義

モデルに一意の属性を追加して、そのモデルの個々のレコードを一意に識別できるようにすることができます。一意の属性は、@unique属性を使用した単一のフィールド、または@@unique属性を使用した複数のフィールド(複合または複合一意制約とも呼ばれます)で定義できます。

次の例では、emailフィールドの値は一意である必要があります

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}

次の例では、authorIdtitleの組み合わせが一意である必要があります

model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
categories Category[] @relation(references: [id])

@@unique([authorId, title])
}
情報

リレーショナルデータベースの制約名
カスタム一意制約名を基盤となるデータベースでオプションで定義できます。

デフォルトでは、Prisma Clientクエリでのこのフィールドの名前はauthorId_titleになります。

@@unique属性のnameフィールドを使用して、複合一意制約の独自の名前を提供することもできます

model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
createdAt DateTime @default(now())
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
categories Category[] @relation(references: [id])

@@unique(name: "authorTitle", [authorId, title])
}

authorId_titleフィールドの名前がauthorTitleに変更されました。

情報

Prisma Clientで複合一意制約を操作する方法については、複合一意識別子の操作に関するドキュメントを参照してください。

複合型一意制約

バージョン3.12.0以降のMongoDBプロバイダーを使用する場合、@@unique([compositeType.field])構文を使用して、複合型のフィールドに一意制約を定義できます。他のフィールドと同様に、複合型フィールドは複数カラムの一意制約の一部として使用できます。

次の例では、Userモデルのemailフィールドと、User.addressで使用されているAddress複合型のnumberフィールドに基づいて、複数カラムの一意制約を定義します

schema.prisma
type Address {
street String
number Int
}

model User {
id Int @id
email String
address Address

@@unique([email, address.number])
}

ネストされた複合型が複数ある場合、この表記法をチェーンできます

schema.prisma
type City {
name String
}

type Address {
number Int
city City
}

model User {
id Int @id
address Address[]

@@unique([address.city.name])
}

インデックスの定義

モデルの1つまたは複数のフィールドにインデックスを定義するには、モデルの@@indexを使用します。次の例では、titleフィールドとcontentフィールドに基づいて複数カラムのインデックスを定義します

model Post {
id Int @id @default(autoincrement())
title String
content String?

@@index([title, content])
}
情報

リレーショナルデータベースのインデックス名
カスタムインデックス名を基盤となるデータベースでオプションで定義できます。

複合型インデックスの定義

バージョン3.12.0以降のMongoDBプロバイダーを使用する場合、@@index([compositeType.field])構文を使用して、複合型のフィールドにインデックスを定義できます。他のフィールドと同様に、複合型フィールドは複数カラムのインデックスの一部として使用できます。

次の例では、Userモデルのemailフィールドと、Address複合型のnumberフィールドに基づいて、複数カラムのインデックスを定義します

schema.prisma
type Address {
street String
number Int
}

model User {
id Int @id
email String
address Address

@@index([email, address.number])
}

ネストされた複合型が複数ある場合、この表記法をチェーンできます

schema.prisma
type City {
name String
}

type Address {
number Int
city City
}

model User {
id Int @id
address Address[]

@@index([address.city.name])
}

Enumの定義

データベースコネクタでEnumがサポートされている場合、データモデルでEnumを定義できます。ネイティブまたはPrisma ORMレベルのいずれかです。

Enumは、Prismaスキーマデータモデルではスカラー型と見なされます。したがって、デフォルトでPrisma Clientクエリのリターン値として含まれています。

Enumは、enumブロックを介して定義されます。たとえば、UserにはRoleがあります

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
role Role @default(USER)
}

enum Role {
USER
ADMIN
}

複合型の定義

情報

複合型は、バージョン3.10.0mongodbプレビュー機能フラグの下に追加され、バージョン3.12.0以降で一般公開されています。

警告

複合型は現在、MongoDBでのみ利用可能です。

複合型(MongoDBでは埋め込みドキュメントとして知られています)は、新しいオブジェクト型を定義できるようにすることで、レコードを他のレコード内に埋め込むためのサポートを提供します。複合型は、モデルと同様の方法で構造化され、型付けされます。

複合型を定義するには、typeブロックを使用します。例として、次のスキーマを見てください

schema.prisma
model Product {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
photos Photo[]
}

type Photo {
height Int
width Int
url String
}

この場合、Productモデルには、photosに格納されたPhoto複合型のリストがあります。

複合型を使用する際の考慮事項

複合型は、属性の限られたセットのみをサポートします。次の属性がサポートされています

次の属性は、複合型内ではサポートされていません

  • @unique
  • @id
  • @relation
  • @ignore
  • @updatedAt

ただし、複合型を使用するモデルのレベルで@@unique属性を使用することで、一意制約を定義できます。詳細については、複合型一意制約を参照してください。

インデックスは、複合型を使用するモデルのレベルで@@index属性を使用することで定義できます。詳細については、複合型インデックスを参照してください。

関数の使用

Prismaスキーマは、多数の関数をサポートしています。これらは、モデルのフィールドにデフォルト値を指定するために使用できます。

たとえば、createdAtのデフォルト値はnow()です

model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
}

cuid()uuid()はPrisma ORMによって実装されているため、基盤となるデータベーススキーマでは「表示」されません。イントロスペクションを使用する場合でも、Prismaスキーマを手動で変更し、Prisma Clientを生成することで使用できます。その場合、値はPrisma Clientのクエリエンジンによって生成されます

autoincrement()now()、およびdbgenerated(...)のサポートは、データベースによって異なります。

リレーショナルデータベースコネクタは、データベースレベルでautoincrement()dbgenerated(...)、およびnow()を実装します。MongoDBコネクタは、autoincrement()またはdbgenerated(...)をサポートしておらず、now()はPrisma ORMレベルで実装されています。auto()関数は、ObjectIdを生成するために使用されます。

リレーション

モデル間のリレーションシップの詳細と例については、リレーションのドキュメントを参照してください。

Prisma Clientのモデル

クエリ(CRUD)

データモデル定義のすべてのモデルは、生成されたPrisma Client APIで多数のCRUDクエリになります

操作は、Prisma Clientインスタンスで生成されたプロパティを介してアクセスできます。デフォルトでは、プロパティの名前はモデル名の小文字形式です。例:Userモデルの場合はuserPostモデルの場合はpost

Prisma Client APIからのuserプロパティの使用例を次に示します

const newUser = await prisma.user.create({
data: {
name: 'Alice',
},
})
const allUsers = await prisma.user.findMany()

型定義

Prisma Clientは、モデル構造を反映する型定義も生成します。これらは、生成された@prisma/client nodeモジュールの一部です。

TypeScriptを使用する場合、これらの型定義により、すべてのデータベースクエリが完全に型安全になり、コンパイル時(selectまたはincludeを使用した部分クエリでも)に検証されるようになります。

プレーンなJavaScriptを使用している場合でも、型定義は@prisma/client nodeモジュールに含まれており、エディターでIntelliSense/オートコンプリートなどの機能が有効になります。

:実際の型は.prisma/clientフォルダーに保存されます。@prisma/client/index.d.tsはこのフォルダーの内容をエクスポートします。

たとえば、上記のUserモデルの型定義は次のようになります

export type User = {
id: number
email: string
name: string | null
role: string
}

リレーションフィールドpostsprofileは、デフォルトでは型定義に含まれていないことに注意してください。ただし、User型のバリエーションが必要な場合は、Prisma Clientの生成されたヘルパー型の一部を使用して定義できます(この場合、これらのヘルパー型はUserGetIncludePayloadおよびUserGetSelectPayloadと呼ばれます)。

制限事項

レコードは一意に識別可能である必要があります

Prisma ORM は現在、少なくとも1つのユニークフィールドまたはフィールドの組み合わせを持つモデルのみをサポートしています。実際には、これはすべての Prisma モデルが以下の属性の少なくとも1つを持つ必要があることを意味します。

  • @id または @@id (単一または複数フィールドの主キー制約、モデルごとに最大1つ)
  • @unique または @@unique (単一または複数フィールドのユニーク制約)