Skip to main content

CRUD

本页介绍如何使用生成的 Prisma 客户端 API 执行 CRUD 操作。CRUD 是一个缩写词,代表:

¥This page describes how to perform CRUD operations with your generated Prisma Client API. CRUD is an acronym that stands for:

有关每种方法的详细说明,请参阅 Prisma 客户端 API 参考文档

¥Refer to the Prisma Client API reference documentation for detailed explanations of each method.

示例架构

¥Example schema

所有示例均基于以下架构:

¥All examples are based on the following schema:

Expand for sample 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 命令将示例模式推送到你自己的数据库

¥For relational databases, use db push command to push the example schema to your own database

npx prisma db push

对于 MongoDB,请确保你的数据具有统一的形状并与 Prisma 架构中定义的模型匹配。

¥For MongoDB, ensure your data is in a uniform shape and matches the model defined in the Prisma schema.

创造

¥Create

创建单个记录

¥Create a single record

以下查询创建 (create()) 具有两个字段的单个用户:

¥The following query creates (create()) a single user with two fields:

const user = await prisma.user.create({
data: {
email: 'elsa@prisma.io',
name: 'Elsa Prisma',
},
})
Show query results

用户的 id 是自动生成的,你的架构确定 哪些字段是必填字段

¥The user's id is auto-generated, and your schema determines which fields are mandatory.

使用生成的类型创建单个记录

¥Create a single record using generated types

以下示例生成相同的结果,但在 create() 查询的上下文之外创建一个名为 userUserCreateInput 变量。完成简单检查(“帖子是否应包含在此 create() 查询中?”)后,user 变量将传递到查询中:

¥The following example produces an identical result, but creates a UserCreateInput variable named user outside the context of the create() query. After completing a simple check ("Should posts be included in this create() query?"), the user variable is passed into the query:

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

有关使用生成类型的更多信息,请参阅:生成的类型

¥For more information about working with generated types, see: Generated types.

创建多条记录

¥Create multiple records

Prisma 客户端支持批量插入作为 2.20.0 及更高版本中的 GA 功能。

¥Prisma Client supports bulk inserts as a GA feature in 2.20.0 and later.

以下 createMany() 查询创建多个用户并跳过任何重复项(email 必须是唯一的):

¥The following createMany() query creates multiple users and skips any duplicates (email must be unique):

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'
})
Show query results
{
count: 3
}
warning

注意 使用 MongoDB、SQLServer 或 SQLite 时不支持 skipDuplicates

¥Note skipDuplicates is not supported when using MongoDB, SQLServer, or SQLite.

createMany() 使用具有多个值的单个 INSERT INTO 语句,这通常比每行单独的 INSERT 更有效:

¥createMany() uses a single INSERT INTO statement with multiple values, which is generally more efficient than a separate INSERT per row:

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 语句。

¥Note: Multiple create() statements inside a $transaction results in multiple INSERT statements.

以下视频演示了如何使用 createMany()faker.js 使用示例数据为数据库播种:

¥The following video demonstrates how to use createMany() and faker.js to seed a database with sample data:

创建记录并连接或创建相关记录

¥Create records and connect or create related records

有关同时创建记录和一个或多个相关记录的信息,请参阅 使用关系 > 嵌套写入

¥See Working with relations > Nested writes for information about creating a record and one or more related records at the same time.

创建并返回多个记录

¥Create and return multiple records

信息

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

¥This feature is available in Prisma ORM version 5.14.0 and later for PostgreSQL, CockroachDB and SQLite.

你可以使用 createManyAndReturn() 创建许多记录并返回结果对象。

¥You can use createManyAndReturn() in order to create many records and return the resulting objects.

const users = await prisma.user.createManyAndReturn({
data: [
{ name: 'Alice', email: 'alice@prisma.io' },
{ name: 'Bob', email: 'bob@prisma.io' },
],
})
Show query results
警告

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

¥relationLoadStrategy: join is not available when using createManyAndReturn().

¥Read

通过 ID 或唯一标识符获取记录

¥Get record by ID or unique identifier

以下查询通过唯一标识符或 ID 返回单个记录 (findUnique()):

¥The following queries return a single record (findUnique()) by unique identifier or ID:

// 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 的字符串表示形式:

¥If you are using the MongoDB connector and your underlying ID type is ObjectId, you can use the string representation of that ObjectId:

// By ID
const user = await prisma.user.findUnique({
where: {
id: '60d5922d00581b8f0062e3a8',
},
})

获取所有记录

¥Get all records

以下 findMany() 查询返回所有 User 记录:

¥The following findMany() query returns all User records:

const users = await prisma.user.findMany()

你也可以 对结果进行分页

¥You can also paginate your results.

获取符合特定条件的第一条记录

¥Get the first record that matches a specific criteria

以下 findFirst() 查询返回最近创建的用户,该用户至少有一篇帖子获得超过 100 个赞:

¥The following findFirst() query returns the most recently created user with at least one post that has more than 100 likes:

  1. 按 ID 降序排列用户(最大的在前) - 最大的 ID 是最新的

    ¥Order users by descending ID (largest first) - the largest ID is the most recent

  2. 按降序返回第一个至少有一个帖子获得超过 100 个赞的用户

    ¥Return the first user in descending order with at least one post that has more than 100 likes

const findUser = await prisma.user.findFirst({
where: {
posts: {
some: {
likes: {
gt: 100,
},
},
},
},
orderBy: {
id: 'desc',
},
})

获取过滤后的记录列表

¥Get a filtered list of records

Prisma 客户端支持记录字段和相关记录字段上的 filtering

¥Prisma Client supports filtering on record fields and related record fields.

按单个字段值过滤

¥Filter by a single field value

以下查询返回电子邮件以 "prisma.io" 结尾的所有 User 记录:

¥The following query returns all User records with an email that ends in "prisma.io":

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

按多个字段值过滤

¥Filter by multiple field values

以下查询使用 operators 的组合返回名称以 E 开头的用户或至少具有 1 个配置文件视图的管理员:

¥The following query uses a combination of operators to return users whose name start with E or administrators with at least 1 profile view:

const users = await prisma.user.findMany({
where: {
OR: [
{
name: {
startsWith: 'E',
},
},
{
AND: {
profileViews: {
gt: 0,
},
role: {
equals: 'ADMIN',
},
},
},
],
},
})

按相关记录字段值过滤

¥Filter by related record field values

以下查询返回电子邮件以 prisma.io 结尾且至少有一个帖子 (some) 未发布的用户:

¥The following query returns users with an email that ends with prisma.io and have at least one post (some) that is not published:

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

有关过滤相关字段值的更多示例,请参阅 与关系合作

¥See Working with relations for more examples of filtering on related field values.

选择字段的子集

¥Select a subset of fields

以下 findUnique() 查询使用 select 返回特定 User 记录的 emailname 字段:

¥The following findUnique() query uses select to return the email and name fields of a specific User record:

const user = await prisma.user.findUnique({
where: {
email: 'emma@prisma.io',
},
select: {
email: true,
name: true,
},
})
Show query results

有关包含关系的更多信息,请参阅:

¥For more information about including relations, refer to:

选择相关记录字段的子集

¥Select a subset of related record fields

以下查询使用嵌套 select 来返回:

¥The following query uses a nested select to return:

  • 用户的 email

    ¥The user's email

  • 每个帖子的 likes 字段

    ¥The likes field of each post

const user = await prisma.user.findUnique({
where: {
email: 'emma@prisma.io',
},
select: {
email: true,
posts: {
select: {
likes: true,
},
},
},
})
Show query results

有关包含关系的更多信息,请参阅 选择字段并包含关系

¥For more information about including relations, see Select fields and include relations.

选择不同的字段值

¥Select distinct field values

有关选择不同字段值的信息,请参阅 选择 distinct

¥See Select distinct for information about selecting distinct field values.

包括相关记录

¥Include related records

以下查询返回所有 ADMIN 用户并在结果中包含每个用户的帖子:

¥The following query returns all ADMIN users and includes each user's posts in the result:

const users = await prisma.user.findMany({
where: {
role: 'ADMIN',
},
include: {
posts: true,
},
})
Show query results

有关包含关系的更多信息,请参阅 选择字段并包含关系

¥For more information about including relations, see Select fields and include relations.

包括过滤的关系列表

¥Include a filtered list of relations

请参阅 与关系合作 以了解如何组合 includewhere 以获取过滤的关系列表 - 例如,仅包含用户发布的帖子。

¥See Working with relations to find out how to combine include and where for a filtered list of relations - for example, only include a user's published posts.

更新

¥Update

更新单条记录

¥Update a single record

以下查询使用 update() 来查找单个 User 记录并通过 email 更新:

¥The following query uses update() to find and update a single User record by email:

const updateUser = await prisma.user.update({
where: {
email: 'viola@prisma.io',
},
data: {
name: 'Viola the Magnificent',
},
})
Show query results

更新多条记录

¥Update multiple records

以下查询使用 updateMany() 更新包含 prisma.io 的所有 User 记录:

¥The following query uses updateMany() to update all User records that contain prisma.io:

const updateUsers = await prisma.user.updateMany({
where: {
email: {
contains: 'prisma.io',
},
},
data: {
role: 'ADMIN',
},
})
Show query results

更新并返回多个记录

¥Update and return multiple records

信息

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

¥This feature is available in Prisma ORM version 6.2.0 and later for PostgreSQL, CockroachDB, and SQLite.

你可以使用 updateManyAndReturn() 来更新许多记录并返回结果对象。

¥You can use updateManyAndReturn() in order to update many records and return the resulting objects.

const users = await prisma.user.updateManyAndReturn({
where: {
email: {
contains: 'prisma.io',
}
},
data: {
role: 'ADMIN'
}
})
Show query results
警告

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

¥relationLoadStrategy: join is not available when using updateManyAndReturn().

更新或创建记录

¥Update or create records

以下查询使用 upsert() 更新具有特定电子邮件地址的 User 记录,或者创建该 User 记录(如果不存在):

¥The following query uses upsert() to update a User record with a specific email address, or create that User record if it does not exist:

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',
},
})
Show query results
info

从版本 4.6.0 开始,Prisma 客户端尽可能使用数据库原生 SQL 命令执行更新插入。了解更多

¥From version 4.6.0, Prisma Client carries out upserts with database native SQL commands where possible. Learn more.

Prisma 客户端没有 findOrCreate() 查询。你可以使用 upsert() 作为解决方法。要使 upsert() 的行为类似于 findOrCreate() 方法,请向 upsert() 提供一个空的 update 参数。

¥Prisma Client does not have a findOrCreate() query. You can use upsert() as a workaround. To make upsert() behave like a findOrCreate() method, provide an empty update parameter to upsert().

warning

使用 upsert() 作为 findOrCreate() 的解决方法的一个限制是 upsert() 将仅接受 where 条件中的唯一模型字段。因此,如果 where 条件包含非唯一字段,则不可能使用 upsert() 来模拟 findOrCreate()

¥A limitation to using upsert() as a workaround for findOrCreate() is that upsert() will only accept unique model fields in the where condition. So it's not possible to use upsert() to emulate findOrCreate() if the where condition contains non-unique fields.

更新数字字段

¥Update a number field

使用 原子序数运算 根据数字字段的当前值更新数字字段 - 例如,递增或乘法。以下查询将 viewslikes 字段增加 1

¥Use atomic number operations to update a number field based on its current value - for example, increment or multiply. The following query increments the views and likes fields by 1:

const updatePosts = await prisma.post.updateMany({
data: {
views: {
increment: 1,
},
likes: {
increment: 1,
},
},
})

连接和断开相关记录

¥Connect and disconnect related records

有关断开(disconnect)和连接(connect)相关记录的信息,请参阅 与关系合作

¥Refer to Working with relations for information about disconnecting (disconnect) and connecting (connect) related records.

删除

¥Delete

删除单条记录

¥Delete a single record

以下查询使用 delete() 删除单个 User 记录:

¥The following query uses delete() to delete a single User record:

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

尝试删除具有一个或多个帖子的用户会导致错误,因为每个 Post 都需要一个作者 - 见 级联删除

¥Attempting to delete a user with one or more posts result in an error, as every Post requires an author - see cascading deletes.

删除多条记录

¥Delete multiple records

以下查询使用 deleteMany() 删除 email 包含 prisma.io 的所有 User 记录:

¥The following query uses deleteMany() to delete all User records where email contains prisma.io:

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

尝试删除具有一个或多个帖子的用户会导致错误,因为每个 Post 都需要一个作者 - 见 级联删除

¥Attempting to delete a user with one or more posts result in an error, as every Post requires an author - see cascading deletes.

删除所有记录

¥Delete all records

以下查询使用 deleteMany() 删除所有 User 记录:

¥The following query uses deleteMany() to delete all User records:

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

请注意,如果用户有任何相关记录(例如帖子),此查询将会失败。在这种情况下,你需要 先删除相关记录

¥Be aware that this query will fail if the user has any related records (such as posts). In this case, you need to delete the related records first.

级联删除(删除相关记录)

¥Cascading deletes (deleting related records)

warning

2.26.0 及更高版本中,可以使用预览功能 参考行动 进行级联删除。

¥In 2.26.0 and later it is possible to do cascading deletes using the preview feature referential actions.

以下查询使用 delete() 删除单个 User 记录:

¥The following query uses delete() to delete a single User record:

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

但是,示例架构包含 PostUser 之间的必需关系,这意味着你无法删除具有帖子的用户:

¥However, the example schema includes a required relation between Post and User, which means that you cannot delete a user with posts:

The change you are trying to make would violate the required relation 'PostToUser' between the `Post` and `User` models.

要解决此错误,你可以:

¥To resolve this error, you can:

  • 使关系可选:

    ¥Make the relation optional:

    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
    }
  • 在删除用户之前,将帖子的作者更改为其他用户。

    ¥Change the author of the posts to another user before deleting the user.

  • 在事务中使用两个单独的查询删除用户及其所有帖子(所有查询必须成功):

    ¥Delete a user and all their posts with two separate queries in a transaction (all queries must succeed):

    const deletePosts = prisma.post.deleteMany({
    where: {
    authorId: 7,
    },
    })

    const deleteUser = prisma.user.delete({
    where: {
    id: 7,
    },
    })

    const transaction = await prisma.$transaction([deletePosts, deleteUser])

删除所有表中的所有记录

¥Delete all records from all tables

有时你想要删除所有表中的所有数据,但保留实际的表。这在开发环境和测试时特别有用。

¥Sometimes you want to remove all data from all tables but keep the actual tables. This can be particularly useful in a development environment and whilst testing.

以下显示如何使用 Prisma Client 和 Prisma Migrate 删除所有表中的所有记录。

¥The following shows how to delete all records from all tables with Prisma Client and with Prisma Migrate.

删除所有带有 deleteMany() 的数据

¥Deleting all data with deleteMany()

当你知道表的删除顺序后,你可以使用 deleteMany 函数。这是在 $transaction 中同步执行的,并且可以与所有类型的数据库一起使用。

¥When you know the order in which your tables should be deleted, you can use the deleteMany function. This is executed synchronously in a $transaction and can be used with all types of databases.

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

✅ 优点:

¥✅ Pros:

  • 当你提前了解架构的结构时效果很好

    ¥Works well when you know the structure of your schema ahead of time

  • 同步删除各表数据

    ¥Synchronously deletes each tables data

❌ 缺点:

¥❌ Cons:

  • 使用关系数据库时,此函数无法扩展,也无法提供更通用的解决方案来查找和 TRUNCATE 表,而不管其关系约束如何。请注意,使用 MongoDB 连接器时,此扩展问题不适用。

    ¥When working with relational databases, this function doesn't scale as well as having a more generic solution which looks up and TRUNCATEs your tables regardless of their relational constraints. Note that this scaling issue does not apply when using the MongoDB connector.

注意:$transaction 对每个模型表执行级联删除,因此必须按顺序调用它们。

¥Note: The $transaction performs a cascading delete on each models table so they have to be called in order.

使用原始 SQL / TRUNCATE 删除所有数据

¥Deleting all data with raw SQL / TRUNCATE

如果你习惯使用原始 SQL,则可以使用 $executeRawUnsafe 对表执行 TRUNCATE 查询。

¥If you are comfortable working with raw SQL, you can perform a TRUNCATE query on a table using $executeRawUnsafe.

在以下示例中,第一个选项卡显示如何通过使用映射表的 $queryRaw 查找以及单个查询中的 TRUNCATES 所有表来对 Postgres 数据库执行 TRUNCATE

¥In the following examples, the first tab shows how to perform a TRUNCATE on a Postgres database by using a $queryRaw look up that maps over the table and TRUNCATES all tables in a single query.

第二个选项卡显示执行相同的功能,但使用 MySQL 数据库。在这种情况下,必须在执行 TRUNCATE 之前删除约束,并在完成后恢复约束。整个过程作为 $transaction 运行

¥The second tab shows performing the same function but with a MySQL database. In this instance the constraints must be removed before the TRUNCATE can be executed, before being reinstated once finished. The whole process is run as a $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 })
}

✅ 优点:

¥✅ Pros:

  • 可扩展

    ¥Scalable

  • 非常快

    ¥Very fast

❌ 缺点:

¥❌ Cons:

  • 无法撤消操作

    ¥Can't undo the operation

  • 尝试运行原始查询时,使用保留的 SQL 关键字作为表名称可能会导致问题

    ¥Using reserved SQL key words as tables names can cause issues when trying to run a raw query

使用 Prisma Migrate 删除所有记录

¥Deleting all records with Prisma Migrate

如果你使用 Prisma Migrate,则可以使用 migrate reset,这将:

¥If you use Prisma Migrate, you can use migrate reset, this will:

  1. 删除数据库

    ¥Drop the database

  2. 创建一个新数据库

    ¥Create a new database

  3. 应用迁移

    ¥Apply migrations

  4. 用数据为数据库播种

    ¥Seed the database with data

高级查询示例

¥Advanced query examples

创建深度嵌套的记录树

¥Create a deeply nested tree of records

  • 单个 User

    ¥A single User

  • 两条新的相关 Post 记录

    ¥Two new, related Post records

  • 每个帖子连接或创建 Category

    ¥Connect or create Category per post

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',
},
},
],
},
},
],
},
},
})