跳到主要內容

CRUD

本頁面描述瞭如何使用生成的 Prisma Client API 執行 CRUD 操作。CRUD 是以下各項的首字母縮寫:

有關每個方法的詳細說明,請參閱Prisma Client API 參考文件

示例 Schema

所有示例均基於以下 schema:

展開檢視示例 schema
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 命令將示例 schema 推送到你自己的資料庫。

npx prisma db push

對於 MongoDB,請確保你的資料形狀統一併與 Prisma schema 中定義的模型匹配。

建立

建立單個記錄

以下查詢建立 (create()) 一個具有兩個欄位的單個使用者:

const user = await prisma.user.create({
data: {
email: 'elsa@prisma.io',
name: 'Elsa Prisma',
},
})
顯示查詢結果

使用者的 id 是自動生成的,你的 schema 決定了哪些欄位是必需的

使用生成的型別建立單個記錄

以下示例產生相同的結果,但建立了一個名為 userUserCreateInput 變數,其位於 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
}
警告

請注意,使用 MongoDB、SQLServer 或 SQLite 時不支援 skipDuplicates

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 來為資料庫播種示例資料:

有關同時建立記錄和一個或多個相關記錄的資訊,請參閱處理關係 > 巢狀寫入

建立並返回多個記錄

資訊

此功能在 Prisma ORM 5.14.0 及更高版本中適用於 PostgreSQL、CockroachDB 和 SQLite。

你可以使用 createManyAndReturn() 來建立多條記錄並返回結果物件。

const users = await prisma.user.createManyAndReturn({
data: [
{ name: 'Alice', email: 'alice@prisma.io' },
{ name: 'Bob', email: 'bob@prisma.io' },
],
})
顯示查詢結果
警告

使用 createManyAndReturn() 時,relationLoadStrategy: join 不可用。

讀取

透過 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 是最新的。
  2. 返回降序排列的第一個使用者,該使用者至少有一篇文章的點贊數超過 100。
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 結尾並且至少有一篇未釋出文章(some)的使用者:

const users = await prisma.user.findMany({
where: {
email: {
endsWith: 'prisma.io',
},
posts: {
some: {
published: false,
},
},
},
})

有關按相關欄位值過濾的更多示例,請參閱處理關係

選擇欄位子集

以下 findUnique() 查詢使用 select 返回特定 User 記錄的 emailname 欄位:

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.ioUser 記錄:

const updateUsers = await prisma.user.updateMany({
where: {
email: {
contains: 'prisma.io',
},
},
data: {
role: 'ADMIN',
},
})
顯示查詢結果

更新並返回多個記錄

資訊

此功能在 Prisma ORM 6.2.0 及更高版本中適用於 PostgreSQL、CockroachDB 和 SQLite。

你可以使用 updateManyAndReturn() 來更新多條記錄並返回結果物件。

const users = await prisma.user.updateManyAndReturn({
where: {
email: {
contains: 'prisma.io',
}
},
data: {
role: 'ADMIN'
}
})
顯示查詢結果
警告

使用 updateManyAndReturn() 時,relationLoadStrategy: join 不可用。

更新建立記錄

以下查詢使用 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()

更新數字欄位

使用原子數字操作來更新基於其當前值的數字欄位——例如,遞增或乘以。以下查詢將 viewslikes 欄位遞增 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',
},
})

嘗試刪除一個或多個帖子的使用者會導致錯誤,因為每個 Post 都需要一個作者——請參閱級聯刪除

刪除多個記錄

以下查詢使用 deleteMany() 刪除所有 email 包含 prisma.ioUser 記錄:

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

嘗試刪除一個或多個帖子的使用者會導致錯誤,因為每個 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',
},
})

然而,示例 schema 中包含 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
    }
  • 在刪除使用者之前,將文章的作者更改為另一個使用者。

  • 透過事務中的兩個獨立查詢(所有查詢必須成功)刪除使用者及其所有文章。

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

優點

  • 當你提前知道 schema 結構時,效果很好。
  • 同步刪除每個表的資料。

缺點

  • 在使用關係型資料庫時,此函式的擴充套件性不如具有更通用的解決方案(該方案查詢並 TRUNCATE 你的表,而不考慮其關係約束)。請注意,使用 MongoDB 聯結器時,此擴充套件性問題不適用。

注意$transaction 對每個模型的表執行級聯刪除,因此必須按順序呼叫它們。

使用原始 SQL / TRUNCATE 刪除所有資料

如果你習慣使用原始 SQL,可以使用 $executeRawUnsafe 對錶執行 TRUNCATE 查詢。

在以下示例中,第一個選項卡展示瞭如何透過使用 $queryRaw 查詢來對 Postgres 資料庫執行 TRUNCATE,該查詢會遍歷表並在單個查詢中 TRUNCATE 所有表。

第二個選項卡展示了執行相同功能但使用 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
  • 兩個新的相關 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',
},
},
],
},
},
],
},
},
})
© . This site is unofficial and not affiliated with Prisma Data, Inc.