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

CRUD

このページでは、生成されたPrisma Client APIでCRUD操作を実行する方法について説明します。 CRUDは、以下の頭字語です。

各メソッドの詳細な説明については、Prisma Client APIリファレンスドキュメントを参照してください。

スキーマ例

すべての例は、次のスキーマに基づいています。

サンプルスキーマを展開
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
}

リレーショナルデータベースの場合、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つある最新の作成されたユーザーを返します。

  1. IDを降順(最大が最初)でユーザーを並べ替えます - 最大のIDが最新です
  2. 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,
},
})
表示クエリ結果

リレーションを含める方法の詳細については、フィールドを選択してリレーションを含めるを参照してください。

フィルタリングされたリレーションリストを含める

フィルタリングされたリレーションリスト(たとえば、ユーザーの公開された投稿のみを含める)のためにincludewhereを組み合わせる方法については、リレーションの操作を参照してください。

更新

単一レコードの更新

次のクエリは、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()を使用して、emailprisma.ioを含むすべてのUserレコードを削除します。

const deleteUsers = await prisma.user.deleteMany({
where: {
email: {
contains: 'prisma.io',
},
},
})

1つ以上の投稿を持つユーザーを削除しようとすると、すべてのPostには作成者が必要であるため、エラーが発生します - カスケード削除を参照してください。

すべてのレコードを削除

次のクエリは、deleteMany()を使用して、すべてのUserレコードを削除します。

const deleteUsers = await prisma.user.deleteMany({})

ユーザーに関連レコード(投稿など)がある場合、このクエリは失敗することに注意してください。 この場合、最初に関連レコードを削除する必要があります。

警告

2.26.0以降では、プレビュー機能参照アクションを使用してカスケード削除を実行できます。

次のクエリは、delete()を使用して、単一のUserレコードを削除します。

const deleteUser = await prisma.user.delete({
where: {
email: 'bert@prisma.io',
},
})

ただし、スキーマ例には、PostUserの間の必須リレーションが含まれています。これは、投稿を持つユーザーを削除できないことを意味します。

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として実行されます。

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 })
}

長所

  • スケーラブル
  • 非常に高速

短所

  • 操作を元に戻すことはできません
  • 予約済みのSQLキーワードをテーブル名として使用すると、生のクエリを実行しようとしたときに問題が発生する可能性があります

Prisma Migrateを使用したすべてのレコードの削除

Prisma Migrateを使用している場合は、migrate resetを使用できます。これにより、以下が実行されます。

  1. データベースをドロップ
  2. 新しいデータベースを作成
  3. 移行を適用
  4. データベースにデータをシード

高度なクエリの例

レコードの深くネストされたツリーを作成

  • 単一の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',
},
},
],
},
},
],
},
},
})