CRUD
本頁面說明如何使用您產生的 Prisma Client API 執行 CRUD 操作。CRUD 是一個縮寫,代表
請參閱 Prisma Client API 參考文件,以取得每個方法的詳細說明。
範例 Schema
所有範例均基於以下 Schema
展開以查看範例 Schema
- 關聯式資料庫
- 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
命令將範例 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 決定了哪些欄位是必填的。
使用產生的類型建立單一記錄
以下範例產生相同的結果,但在 create()
查詢的上下文之外建立名為 user
的 UserCreateInput
變數。在完成簡單的檢查(「此 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 個
- 依遞減 ID(最大優先)排序使用者 - 最大的 ID 是最新的
- 傳回遞減排序中,至少有一篇貼文的讚數超過 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
記錄的 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',
},
})
更新並傳回多個記錄
此功能在 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()
。
更新數字欄位
使用原子數字運算來根據其目前值更新數字欄位 - 例如,遞增或乘法。以下查詢將 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',
},
})
嘗試刪除具有一篇或多篇貼文的使用者會導致錯誤,因為每篇 Post
都需要作者 - 請參閱串聯刪除。
刪除多個記錄
以下查詢使用 deleteMany()
來刪除 email
包含 prisma.io
的所有 User
記錄
const deleteUsers = await prisma.user.deleteMany({
where: {
email: {
contains: 'prisma.io',
},
},
})
嘗試刪除具有一篇或多篇貼文的使用者會導致錯誤,因為每篇 Post
都需要作者 - 請參閱串聯刪除。
刪除所有記錄
以下查詢使用 deleteMany()
來刪除所有 User
記錄
const deleteUsers = await prisma.user.deleteMany({})
請注意,如果使用者有任何關聯記錄(例如貼文),此查詢將會失敗。在這種情況下,您需要先刪除關聯記錄。
串聯刪除(刪除關聯記錄)
以下查詢使用 delete()
來刪除單一 User
記錄
const deleteUser = await prisma.user.delete({
where: {
email: 'bert@prisma.io',
},
})
但是,範例 Schema 包含 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
} -
在刪除使用者之前,將貼文的作者變更為其他使用者。
-
在交易中以兩個不同的查詢刪除使用者及其所有貼文(所有查詢都必須成功)
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
形式執行
- 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
,這將會
- Drop 資料庫
- 建立新的資料庫
- 套用遷移
- 使用資料植入資料庫
進階查詢範例
建立深度巢狀的記錄樹狀結構
- 單一
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',
},
},
],
},
},
],
},
},
})