CRUD
このページでは、生成されたPrisma Client APIでCRUD操作を実行する方法について説明します。 CRUDは、以下の頭字語です。
各メソッドの詳細な説明については、Prisma Client APIリファレンスドキュメントを参照してください。
スキーマ例
すべての例は、次のスキーマに基づいています。
サンプルスキーマを展開
- リレーショナルデータベース
- MongoDB
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model ExtendedProfile {
id Int @id @default(autoincrement())
biography String
user User @relation(fields: [userId], references: [id])
userId Int @unique
}
model User {
id Int @id @default(autoincrement())
name String?
email String @unique
profileViews Int @default(0)
role Role @default(USER)
coinflips Boolean[]
posts Post[]
profile ExtendedProfile?
}
model Post {
id Int @id @default(autoincrement())
title String
published Boolean @default(true)
author User @relation(fields: [authorId], references: [id])
authorId Int
comments Json?
views Int @default(0)
likes Int @default(0)
categories Category[]
}
model Category {
id Int @id @default(autoincrement())
name String @unique
posts Post[]
}
enum Role {
USER
ADMIN
}
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model ExtendedProfile {
id String @id @default(auto()) @map("_id") @db.ObjectId
biography String
user User @relation(fields: [userId], references: [id])
userId String @unique @db.ObjectId
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String?
email String @unique
profileViews Int @default(0)
role Role @default(USER)
coinflips Boolean[]
posts Post[]
profile ExtendedProfile?
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
published Boolean @default(true)
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
comments Json?
views Int @default(0)
likes Int @default(0)
categories Category[]
}
model Category {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String @unique
posts Post[]
}
enum Role {
USER
ADMIN
}
リレーショナルデータベースの場合、db push
コマンドを使用して、サンプルスキーマを独自のデータベースにプッシュします。
npx prisma db push
MongoDBの場合、データが均一な形状であり、Prismaスキーマで定義されたモデルと一致していることを確認してください。
作成
単一レコードの作成
次のクエリは、2つのフィールドを持つ単一のユーザーを(create()
)作成します。
const user = await prisma.user.create({
data: {
email: 'elsa@prisma.io',
name: 'Elsa Prisma',
},
})
ユーザーのid
は自動生成され、スキーマによって必須フィールドが決まります。
生成された型を使用した単一レコードの作成
次の例は、同じ結果を生成しますが、UserCreateInput
という名前のuser
変数をcreate()
クエリのコンテキスト外で作成します。 簡単なチェック(「このcreate()
クエリに投稿を含める必要がありますか?」)を完了すると、user
変数がクエリに渡されます。
import { PrismaClient, Prisma } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
let includePosts: boolean = false
let user: Prisma.UserCreateInput
// Check if posts should be included in the query
if (includePosts) {
user = {
email: 'elsa@prisma.io',
name: 'Elsa Prisma',
posts: {
create: {
title: 'Include this post!',
},
},
}
} else {
user = {
email: 'elsa@prisma.io',
name: 'Elsa Prisma',
}
}
// Pass 'user' object into query
const createUser = await prisma.user.create({ data: user })
}
main()
生成された型の操作の詳細については、生成された型を参照してください。
複数レコードの作成
Prisma Clientは、2.20.0以降でGA機能として一括挿入をサポートしています。
次のcreateMany()
クエリは、複数のユーザーを作成し、重複(email
は一意である必要があります)をスキップします。
const createMany = await prisma.user.createMany({
data: [
{ name: 'Bob', email: 'bob@prisma.io' },
{ name: 'Bobo', email: 'bob@prisma.io' }, // Duplicate unique key!
{ name: 'Yewande', email: 'yewande@prisma.io' },
{ name: 'Angelique', email: 'angelique@prisma.io' },
],
skipDuplicates: true, // Skip 'Bobo'
})
{
count: 3
}
skipDuplicates
は、MongoDB、SQLServer、またはSQLiteを使用している場合はサポートされていないことに注意してください。
createMany()
は、複数の値を持つ単一のINSERT INTO
ステートメントを使用します。これは通常、行ごとに個別のINSERT
よりも効率的です。
BEGIN
INSERT INTO "public"."User" ("id","name","email","profileViews","role","coinflips","testing","city","country") VALUES (DEFAULT,$1,$2,$3,$4,DEFAULT,DEFAULT,DEFAULT,$5), (DEFAULT,$6,$7,$8,$9,DEFAULT,DEFAULT,DEFAULT,$10), (DEFAULT,$11,$12,$13,$14,DEFAULT,DEFAULT,DEFAULT,$15), (DEFAULT,$16,$17,$18,$19,DEFAULT,DEFAULT,DEFAULT,$20) ON CONFLICT DO NOTHING
COMMIT
SELECT "public"."User"."country", "public"."User"."city", "public"."User"."email", SUM("public"."User"."profileViews"), COUNT(*) FROM "public"."User" WHERE 1=1 GROUP BY "public"."User"."country", "public"."User"."city", "public"."User"."email" HAVING AVG("public"."User"."profileViews") >= $1 ORDER BY "public"."User"."country" ASC OFFSET $2
注:
$transaction
内の複数のcreate()
ステートメントは、複数のINSERT
ステートメントになります。
次のビデオでは、createMany()
とfaker.jsを使用してデータベースにサンプルデータをシードする方法を示します。
レコードを作成し、関連レコードを接続または作成する
レコードと1つ以上の関連レコードを同時に作成する方法については、リレーションの操作 > ネストされた書き込みを参照してください。
複数レコードを作成して返す
この機能は、PostgreSQL、CockroachDB、およびSQLite用のPrisma ORMバージョン5.14.0以降で利用可能です。
createManyAndReturn()
を使用すると、多数のレコードを作成し、結果のオブジェクトを返すことができます。
const users = await prisma.user.createManyAndReturn({
data: [
{ name: 'Alice', email: 'alice@prisma.io' },
{ name: 'Bob', email: 'bob@prisma.io' },
],
})
relationLoadStrategy: join
は、createManyAndReturn()
を使用する場合は使用できません。
読み取り
IDまたはユニーク識別子でレコードを取得
次のクエリは、ユニーク識別子またはIDによって単一のレコード(findUnique()
)を返します。
// By unique identifier
const user = await prisma.user.findUnique({
where: {
email: 'elsa@prisma.io',
},
})
// By ID
const user = await prisma.user.findUnique({
where: {
id: 99,
},
})
MongoDBコネクタを使用しており、基になるID型がObjectId
の場合、そのObjectId
の文字列表現を使用できます。
// By ID
const user = await prisma.user.findUnique({
where: {
id: '60d5922d00581b8f0062e3a8',
},
})
すべてのレコードを取得
次のfindMany()
クエリは、すべてのUser
レコードを返します。
const users = await prisma.user.findMany()
結果をページ分割することもできます。
特定の基準に一致する最初のレコードを取得
次のfindFirst()
クエリは、100以上のいいねがある投稿が少なくとも1つある最新の作成されたユーザーを返します。
- IDを降順(最大が最初)でユーザーを並べ替えます - 最大のIDが最新です
- 100以上のいいねがある投稿が少なくとも1つある最初のユーザーを降順で返します
const findUser = await prisma.user.findFirst({
where: {
posts: {
some: {
likes: {
gt: 100,
},
},
},
},
orderBy: {
id: 'desc',
},
})
フィルタリングされたレコードリストを取得
Prisma Clientは、レコードフィールドと関連レコードフィールドのフィルタリングをサポートしています。
単一フィールド値でフィルタリング
次のクエリは、メールが"prisma.io"
で終わるすべてのUser
レコードを返します。
const users = await prisma.user.findMany({
where: {
email: {
endsWith: 'prisma.io',
},
},
})
複数フィールド値でフィルタリング
次のクエリは、演算子の組み合わせを使用して、名前がE
で始まるユーザーまたは少なくとも1つのプロファイルビューを持つ管理者を返します。
const users = await prisma.user.findMany({
where: {
OR: [
{
name: {
startsWith: 'E',
},
},
{
AND: {
profileViews: {
gt: 0,
},
role: {
equals: 'ADMIN',
},
},
},
],
},
})
関連レコードフィールド値でフィルタリング
次のクエリは、メールがprisma.io
で終わり、かつ公開されていない投稿が少なくとも1つ(some
)あるユーザーを返します。
const users = await prisma.user.findMany({
where: {
email: {
endsWith: 'prisma.io',
},
posts: {
some: {
published: false,
},
},
},
})
関連フィールド値のフィルタリングの例については、リレーションの操作を参照してください。
フィールドのサブセットを選択
次のfindUnique()
クエリは、select
を使用して、特定のUser
レコードのemail
フィールドとname
フィールドを返します。
const user = await prisma.user.findUnique({
where: {
email: 'emma@prisma.io',
},
select: {
email: true,
name: true,
},
})
リレーションを含める方法の詳細については、以下を参照してください。
関連レコードフィールドのサブセットを選択
次のクエリは、ネストされたselect
を使用して、以下を返します。
- ユーザーの
email
- 各投稿の
likes
フィールド
const user = await prisma.user.findUnique({
where: {
email: 'emma@prisma.io',
},
select: {
email: true,
posts: {
select: {
likes: true,
},
},
},
})
リレーションを含める方法の詳細については、フィールドを選択してリレーションを含めるを参照してください。
個別のフィールド値を選択
個別のフィールド値の選択の詳細については、distinct
を選択を参照してください。
関連レコードを含める
次のクエリは、すべてのADMIN
ユーザーを返し、結果に各ユーザーの投稿を含めます。
const users = await prisma.user.findMany({
where: {
role: 'ADMIN',
},
include: {
posts: true,
},
})
リレーションを含める方法の詳細については、フィールドを選択してリレーションを含めるを参照してください。
フィルタリングされたリレーションリストを含める
フィルタリングされたリレーションリスト(たとえば、ユーザーの公開された投稿のみを含める)のためにinclude
とwhere
を組み合わせる方法については、リレーションの操作を参照してください。
更新
単一レコードの更新
次のクエリは、update()
を使用して、email
で単一のUser
レコードを検索して更新します。
const updateUser = await prisma.user.update({
where: {
email: 'viola@prisma.io',
},
data: {
name: 'Viola the Magnificent',
},
})
複数レコードの更新
次のクエリは、updateMany()
を使用して、prisma.io
を含むすべてのUser
レコードを更新します。
const updateUsers = await prisma.user.updateMany({
where: {
email: {
contains: 'prisma.io',
},
},
data: {
role: 'ADMIN',
},
})
複数レコードを更新して返す
この機能は、PostgreSQL、CockroachDB、およびSQLite用のPrisma ORMバージョン6.2.0以降で利用可能です。
updateManyAndReturn()
を使用すると、多数のレコードを更新し、結果のオブジェクトを返すことができます。
const users = await prisma.user.updateManyAndReturn({
where: {
email: {
contains: 'prisma.io',
}
},
data: {
role: 'ADMIN'
}
})
relationLoadStrategy: join
は、updateManyAndReturn()
を使用する場合は使用できません。
レコードを更新または作成する
次のクエリは、upsert()
を使用して、特定のメールアドレスを持つUser
レコードを更新するか、そのUser
レコードが存在しない場合は作成します。
const upsertUser = await prisma.user.upsert({
where: {
email: 'viola@prisma.io',
},
update: {
name: 'Viola the Magnificent',
},
create: {
email: 'viola@prisma.io',
name: 'Viola the Magnificent',
},
})
バージョン4.6.0以降、Prisma Clientは可能な場合、データベースネイティブのSQLコマンドでupsertを実行します。詳細はこちら。
Prisma ClientにはfindOrCreate()
クエリはありません。 回避策としてupsert()
を使用できます。 upsert()
をfindOrCreate()
メソッドのように動作させるには、upsert()
に空のupdate
パラメーターを指定します。
upsert()
をfindOrCreate()
の回避策として使用する場合の制限は、upsert()
がwhere
条件で一意のモデルフィールドのみを受け入れることです。 そのため、where
条件に一意でないフィールドが含まれている場合、upsert()
を使用してfindOrCreate()
をエミュレートすることはできません。
数値フィールドを更新
原子数値演算を使用して、数値フィールドを現在の値に基づいて更新します(たとえば、インクリメントまたは乗算)。 次のクエリは、views
フィールドとlikes
フィールドを1
ずつインクリメントします。
const updatePosts = await prisma.post.updateMany({
data: {
views: {
increment: 1,
},
likes: {
increment: 1,
},
},
})
関連レコードを接続および切断する
関連レコードを切断(disconnect
)および接続(connect
)する方法については、リレーションの操作を参照してください。
削除
単一レコードの削除
次のクエリは、delete()
を使用して、単一のUser
レコードを削除します。
const deleteUser = await prisma.user.delete({
where: {
email: 'bert@prisma.io',
},
})
1つ以上の投稿を持つユーザーを削除しようとすると、すべてのPost
には作成者が必要であるため、エラーが発生します - カスケード削除を参照してください。
複数レコードの削除
次のクエリは、deleteMany()
を使用して、email
にprisma.io
を含むすべてのUser
レコードを削除します。
const deleteUsers = await prisma.user.deleteMany({
where: {
email: {
contains: 'prisma.io',
},
},
})
1つ以上の投稿を持つユーザーを削除しようとすると、すべてのPost
には作成者が必要であるため、エラーが発生します - カスケード削除を参照してください。
すべてのレコードを削除
次のクエリは、deleteMany()
を使用して、すべてのUser
レコードを削除します。
const deleteUsers = await prisma.user.deleteMany({})
ユーザーに関連レコード(投稿など)がある場合、このクエリは失敗することに注意してください。 この場合、最初に関連レコードを削除する必要があります。
カスケード削除(関連レコードの削除)
次のクエリは、delete()
を使用して、単一のUser
レコードを削除します。
const deleteUser = await prisma.user.delete({
where: {
email: 'bert@prisma.io',
},
})
ただし、スキーマ例には、Post
とUser
の間の必須リレーションが含まれています。これは、投稿を持つユーザーを削除できないことを意味します。
The change you are trying to make would violate the required relation 'PostToUser' between the `Post` and `User` models.
このエラーを解決するには、次のことができます。
-
リレーションをオプションにする
model Post {
id Int @id @default(autoincrement())
author User? @relation(fields: [authorId], references: [id])
authorId Int?
author User @relation(fields: [authorId], references: [id])
authorId Int
} -
ユーザーを削除する前に、投稿の作成者を別のユーザーに変更します。
-
トランザクションで2つの別々のクエリを使用して、ユーザーとそのすべての投稿を削除します(すべてのクエリが成功する必要があります)。
const deletePosts = prisma.post.deleteMany({
where: {
authorId: 7,
},
})
const deleteUser = prisma.user.delete({
where: {
id: 7,
},
})
const transaction = await prisma.$transaction([deletePosts, deleteUser])
すべてのテーブルからすべてのレコードを削除
テーブル自体は保持したまま、すべてのテーブルからすべてのデータを削除したい場合があります。 これは、特に開発環境やテスト中に役立ちます。
以下に、Prisma ClientおよびPrisma Migrateを使用してすべてのテーブルからすべてのレコードを削除する方法を示します。
deleteMany()
を使用したすべてのデータの削除
テーブルを削除する順序がわかっている場合は、deleteMany
関数を使用できます。 これは、$transaction
で同期的に実行され、すべてのタイプのデータベースで使用できます。
const deletePosts = prisma.post.deleteMany()
const deleteProfile = prisma.profile.deleteMany()
const deleteUsers = prisma.user.deleteMany()
// The transaction runs synchronously so deleteUsers must run last.
await prisma.$transaction([deleteProfile, deletePosts, deleteUsers])
✅ 長所
- スキーマの構造を事前に知っている場合にうまく機能します
- 各テーブルのデータを同期的に削除します
❌ 短所
- リレーショナルデータベースを操作する場合、この関数は、リレーショナル制約に関係なくテーブルをルックアップして
TRUNCATE
する、より一般的なソリューションほどスケールしません。 このスケーリングの問題は、MongoDBコネクタを使用する場合は適用されないことに注意してください。
注:
$transaction
は、各モデルテーブルでカスケード削除を実行するため、順番に呼び出す必要があります。
生のSQL / TRUNCATE
を使用したすべてのデータの削除
生のSQLの操作に慣れている場合は、$executeRawUnsafe
を使用してテーブルでTRUNCATE
クエリを実行できます。
次の例では、最初のタブは、テーブルをマッピングし、単一のクエリですべてのテーブルをTRUNCATE
する$queryRaw
ルックアップを使用して、PostgresデータベースでTRUNCATE
を実行する方法を示しています。
2番目のタブは、同じ機能をMySQLデータベースで実行する方法を示しています。 このインスタンスでは、TRUNCATE
を実行する前に制約を削除する必要があり、完了したら再度有効にする必要があります。 プロセス全体が$transaction
として実行されます。
- PostgreSQL
- MySQL
const tablenames = await prisma.$queryRaw<
Array<{ tablename: string }>
>`SELECT tablename FROM pg_tables WHERE schemaname='public'`
const tables = tablenames
.map(({ tablename }) => tablename)
.filter((name) => name !== '_prisma_migrations')
.map((name) => `"public"."${name}"`)
.join(', ')
try {
await prisma.$executeRawUnsafe(`TRUNCATE TABLE ${tables} CASCADE;`)
} catch (error) {
console.log({ error })
}
const transactions: PrismaPromise<any>[] = []
transactions.push(prisma.$executeRaw`SET FOREIGN_KEY_CHECKS = 0;`)
const tablenames = await prisma.$queryRaw<
Array<{ TABLE_NAME: string }>
>`SELECT TABLE_NAME from information_schema.TABLES WHERE TABLE_SCHEMA = 'tests';`
for (const { TABLE_NAME } of tablenames) {
if (TABLE_NAME !== '_prisma_migrations') {
try {
transactions.push(prisma.$executeRawUnsafe(`TRUNCATE ${TABLE_NAME};`))
} catch (error) {
console.log({ error })
}
}
}
transactions.push(prisma.$executeRaw`SET FOREIGN_KEY_CHECKS = 1;`)
try {
await prisma.$transaction(transactions)
} catch (error) {
console.log({ error })
}
✅ 長所
- スケーラブル
- 非常に高速
❌ 短所
- 操作を元に戻すことはできません
- 予約済みのSQLキーワードをテーブル名として使用すると、生のクエリを実行しようとしたときに問題が発生する可能性があります
Prisma Migrateを使用したすべてのレコードの削除
Prisma Migrateを使用している場合は、migrate reset
を使用できます。これにより、以下が実行されます。
- データベースをドロップ
- 新しいデータベースを作成
- 移行を適用
- データベースにデータをシード
高度なクエリの例
レコードの深くネストされたツリーを作成
- 単一の
User
- 2つの新しい、関連する
Post
レコード - 投稿ごとに
Category
を接続または作成
const u = await prisma.user.create({
include: {
posts: {
include: {
categories: true,
},
},
},
data: {
email: 'emma@prisma.io',
posts: {
create: [
{
title: 'My first post',
categories: {
connectOrCreate: [
{
create: { name: 'Introductions' },
where: {
name: 'Introductions',
},
},
{
create: { name: 'Social' },
where: {
name: 'Social',
},
},
],
},
},
{
title: 'How to make cookies',
categories: {
connectOrCreate: [
{
create: { name: 'Social' },
where: {
name: 'Social',
},
},
{
create: { name: 'Cooking' },
where: {
name: 'Cooking',
},
},
],
},
},
],
},
},
})