Prisma Client API 参考
Prisma Client API 参考文档基于以下 schema
model User {
id Int @id @default(autoincrement())
name String?
email String @unique
profileViews Int @default(0)
role Role @default(USER)
coinflips Boolean[]
posts Post[]
city String
country String
profile ExtendedProfile?
pets Json
}
model ExtendedProfile {
id Int @id @default(autoincrement())
userId Int? @unique
bio String?
User User? @relation(fields: [userId], references: [id])
}
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)
}
enum Role {
USER
ADMIN
}
所有示例生成的类型(例如 UserSelect
和 UserWhereUniqueInput
)都基于 User
模型。
PrismaClient
本节描述 PrismaClient
构造函数及其参数。
备注
- 参数在运行时验证。
datasources
以编程方式覆盖 schema.prisma
文件中 datasource
块的属性 - 例如,作为集成测试的一部分。另请参阅:数据源
从版本 5.2.0 及更高版本开始,您还可以使用 datasourceUrl
属性以编程方式覆盖数据库连接字符串。
属性
示例属性 | 示例值 | 描述 |
---|---|---|
db | { url: 'file:./dev_qa.db' } | 数据库连接 URL。 |
备注
- 每次添加或重命名数据源时,都必须重新生成 Prisma Client。数据源名称包含在生成的客户端中。
- 如果在 schema 中将
datasource
块命名为其他名称,请将db
替换为您的datasource
块的名称。
示例
以编程方式覆盖数据源 url
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({
datasources: {
db: {
url: 'file:./dev_qa.db',
},
},
});
基于以下 datasource
块
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
datasourceUrl
以编程方式覆盖 schema.prisma
文件中的 datasource
块。
属性
选项 | 示例值 | 描述 |
---|---|---|
数据库连接字符串 | 'file:./dev_qa.db' | 数据库连接 URL。 |
示例
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({
datasourceUrl: 'postgresql://johndoe:randompassword@localhost:5432/mydb',
});
log
确定日志记录的类型和级别。另请参阅:日志记录
选项
选项 | 示例 |
---|---|
日志级别数组 | [ "info", "query" ] |
日志定义数组 | [ { level: "info", emit: "event" }, { level: "warn", emit: "stdout" }] |
日志级别
名称 | 示例 |
---|---|
query | 记录 Prisma 运行的所有查询。 对于关系型数据库,这将记录所有 SQL 查询。示例 prisma:query SELECT "public"."User"."id", "public"."User"."email" FROM "public"."User" WHERE ("public"."User"."id") IN (SELECT "t0"."id" FROM "public"."User" AS "t0" INNER JOIN "public"."Post" AS "j0" ON ("j0"."authorId") = ("t0"."id") WHERE ("j0"."views" > $1 AND "t0"."id" IS NOT NULL)) OFFSET $2 对于 MongoDB,这将使用 mongosh shell 格式记录查询。示例prisma:query db.User.deleteMany({ _id: ( $in: [ “6221ce49f756b0721fc00542”, ], }, }) |
info | 示例prisma:info Started http server on http://127.0.0.1:58471 |
warn | 警告。 |
error | 错误。 |
发出格式
名称 | 描述 |
---|---|
stdout | 参见:stdout |
event | 触发一个可以订阅的事件。 |
事件类型
query
事件类型
export type QueryEvent = {
timestamp: Date;
query: string; // Query sent to the database
params: string; // Query parameters
duration: number; // Time elapsed (in milliseconds) between client issuing query and database responding - not only time taken to run query
target: string;
};
请注意,对于 MongoDB,params
和 duration
字段将是 undefined。
所有其他日志级别事件类型
export type LogEvent = {
timestamp: Date;
message: string;
target: string;
};
示例
将 query
和 info
记录到 stdout
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({ log: ['query', 'info'] });
async function main() {
const countUsers = await prisma.user.count({});
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
将 query
事件记录到控制台
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({
log: [{ level: 'query', emit: 'event' }],
});
prisma.$on('query', (e) => {
console.log(e);
});
async function main() {
const countUsers = await prisma.user.count({});
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
将 info
, warn
和 error
事件记录到控制台
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({
log: [
{ level: 'warn', emit: 'event' },
{ level: 'info', emit: 'event' },
{ level: 'error', emit: 'event' },
],
});
prisma.$on('warn', (e) => {
console.log(e);
});
prisma.$on('info', (e) => {
console.log(e);
});
prisma.$on('error', (e) => {
console.log(e);
});
async function main() {
const countUsers = await prisma.user.count({});
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
errorFormat
确定 Prisma Client 返回错误的级别和格式。
错误格式
名称 | 描述 |
---|---|
undefined | 如果未定义,默认为无颜色。 |
pretty | 启用漂亮错误格式化。 |
colorless (默认) | 启用无颜色错误格式化。 |
minimal | 启用极简错误格式化。 |
示例
无错误格式化
const prisma = new PrismaClient({
// Defaults to colorless
});
pretty
错误格式化
const prisma = new PrismaClient({
errorFormat: 'pretty',
});
colorless
错误格式化
const prisma = new PrismaClient({
errorFormat: 'colorless',
});
minimal
错误格式化
const prisma = new PrismaClient({
errorFormat: 'minimal',
});
adapter
此功能从版本 5.4.0 及更高版本开始可用,需要启用 driverAdapters
功能标志。
示例
以下示例使用Neon 驱动适配器
import { PrismaNeon } from '@prisma/adapter-neon';
import { PrismaClient } from '@prisma/client';
import dotenv from 'dotenv';
dotenv.config();
const connectionString = `${process.env.DATABASE_URL}`;
const adapter = new PrismaNeon({ connectionString });
const prisma = new PrismaClient({ adapter });
rejectOnNotFound
注意:rejectOnNotFound
在 v5.0.0 中已移除。
已弃用: rejectOnNotFound
在 v4.0.0 中已弃用。从 v4.0.0 开始,请使用查询 findUniqueOrThrow
或 findFirstOrThrow
。
使用 rejectOnNotFound
参数配置 findUnique()
和/或 findFirst
,以便在找不到记录时抛出错误。默认情况下,如果找不到记录,这两个操作都返回 null
。
备注
- 您可以针对
findUnique()
和findFirst
在每个请求级别配置rejectOnNotFound
选项
选项 | 描述 |
---|---|
RejectOnNotFound | 全局启用 (true / false ) 或 抛出自定义错误。 |
RejectPerOperation | 按操作启用 (true / false ) 或 按操作、按模型抛出自定义错误。 |
示例
为 findUnique()
和 findFirst
全局启用
const prisma = new PrismaClient({
rejectOnNotFound: true,
});
为特定操作全局启用
const prisma = new PrismaClient({
rejectOnNotFound: {
findUnique: true,
},
});
如果找不到记录,则按模型和操作抛出自定义错误
const prisma = new PrismaClient({
rejectOnNotFound: {
findFirst: {
User: (err) => new Error('User error'),
Post: (err) => new Error('Post error!'),
},
findUnique: {
User: (err) => new Error('User error'),
Post: (err) => new Error('Post error!'),
},
},
});
transactionOptions
注意:transactionOptions
在 v5.10.0 中引入。
允许在构造函数级别全局设置事务选项。
备注
- 事务级别可以在每个事务级别上覆盖。
选项
选项 | 描述 |
---|---|
maxWait | Prisma Client 等待从数据库获取事务的最长时间。默认值为 2 秒。 |
timeout | 交互式事务在被取消和回滚之前可以运行的最长时间。默认值为 5 秒。 |
isolationLevel | 设置事务隔离级别。默认情况下,这被设置为数据库中当前配置的值。可用级别可能因您使用的数据库而异。 |
示例
const prisma = new PrismaClient({
transactionOptions: {
isolationLevel: Prisma.TransactionIsolationLevel.Serializable,
maxWait: 5000, // default: 2000
timeout: 10000, // default: 5000
},
});
模型查询
使用模型查询对模型执行 CRUD 操作。另请参阅:CRUD
注意:最佳实践是在将任何不受信任的用户数据传递给 Prisma 查询之前,始终验证和清洗它们。否则,如果绕过类型检查,可能导致 SQL 注入或其他注入漏洞。请确保用户提供的值不会意外绕过关键检查。我们强烈建议在应用层进行类型检查和输入验证。更多详情,请参阅自定义验证部分。
findUnique()
findUnique()
查询允许您检索单个数据库记录
- 按 ID
- 按 唯一 属性
findUnique()
在版本 2.12.0 中替换了 findOne
。
备注
- Prisma Client 的 dataloader 自动批量处理具有相同
select
和where
参数的findUnique()
查询。 - 如果您希望在找不到记录时查询抛出错误,请考虑改用
findUniqueOrThrow
。 - 您不能使用过滤条件(例如
equals
、contains
、not
)过滤 JSON 数据类型的字段。使用过滤条件可能会导致该字段返回null
。
选项
名称 | 示例类型 (User ) | 必填 | 描述 |
---|---|---|---|
where | UserWhereUniqueInput | 是 | 包装模型的所有字段,以便可以选择记录(了解更多)。 在版本 4.5.0 之前,此类型仅包装模型的 唯一 字段。 |
select | XOR<UserSelect, null> | 否 | 指定返回对象中包含哪些属性。 |
include | XOR<UserInclude, null> | 否 | 指定返回对象中应预加载哪些关系。 |
omit | XOR<UserOmit, null> | 否 | 指定返回对象中排除哪些属性。自 5.13.0 起在预览中。 |
relationLoadStrategy | 'join' 或 'query' | 否 | 默认:join 。指定关联查询的加载策略。仅与 include (或关联字段上的 select )结合使用时可用。自 5.9.0 起在预览中。 |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
JavaScript 对象(类型化) | User | |
JavaScript 对象(普通) | { title: "Hello world" } | 使用 select 和 include 来确定返回哪些字段。 |
null | null | 未找到记录 |
示例
获取 id
为 42
的 User
记录
const result = await prisma.user.findUnique({
where: {
id: 42,
},
});
获取 email
为 alice@prisma.io
的 User
记录
const result = await prisma.user.findUnique({
where: {
email: 'alice@prisma.io',
},
});
获取 firstName
为 Alice
且 lastName
为 Smith
的 User
记录 (@@unique
)
展开带有 @@unique 块的 User 模型示例
model User {
firstName String
lastName String
@@unique(fields: [firstName, lastName], name: "fullname")
}
const result = await prisma.user.findUnique({
where: {
fullname: {
// name property of @@unique attribute - default is firstname_lastname
firstName: 'Alice',
lastName: 'Smith',
},
},
});
获取 firstName
为 Alice
且 lastName
为 Smith
的 User
记录 (@@id
)
展开带有 @@id 块的 User 模型示例
model User {
firstName String
lastName String
@@id([firstName, lastName])
}
const result = await prisma.user.findUnique({
where: {
firstName_lastName: {
firstName: 'Alice',
lastName: 'Smith',
},
},
});
findUniqueOrThrow()
findUniqueOrThrow()
以与 findUnique()
相同的方式检索单个记录。但是,如果查询未找到请求的记录,它会抛出 PrismaClientKnownRequestError
。
请注意,在 Prisma v6 之前,它会抛出 NotFoundError: No User found error
。
以下是其用法示例
await prisma.user.findUniqueOrThrow({
where: { id: 1 },
});
findUniqueOrThrow()
与 findUnique()
的区别如下
-
其返回类型不可为空。例如,
post.findUnique()
可以返回post
或null
,但post.findUniqueOrThrow()
总是返回post
。 -
它与
$transaction
API 中的顺序操作不兼容。如果查询抛出PrismaClientKnownRequestError
,则 API 不会回滚调用数组中的任何操作。作为一种变通方法,您可以按如下方式将交互式事务与$transaction
API 一起使用$transaction(async (prisma) => {
await prisma.model.create({ data: { ... });
await prisma.model.findUniqueOrThrow();
})
findFirst()
findFirst
返回列表中符合您条件的第一个记录。
备注
- 如果您希望在找不到记录时查询抛出错误,请考虑改用
findFirstOrThrow
。
选项
名称 | 示例类型 (User ) | 必填 | 描述 |
---|---|---|---|
select | XOR<UserSelect, null> | 否 | 指定返回对象中包含哪些属性。 |
include | XOR<UserInclude, null> | 否 | 指定返回对象中应预加载哪些关系。 |
omit | XOR<UserOmit, null> | 否 | 指定返回对象中排除哪些属性。自 5.13.0 起在预览中。 |
relationLoadStrategy | 'join' 或 'query' | 否 | 默认:join 。指定关联查询的加载策略。仅与 include (或关联字段上的 select )结合使用时可用。自 5.9.0 起在预览中。 |
where | UserWhereInput | 否 | 将 所有 模型字段包装在类型中,以便列表可以通过任何属性进行过滤。 |
orderBy | XOR<Enumerable<UserOrderByInput>, UserOrderByInput> | 否 | 允许您按任何属性对返回的列表进行排序。 |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
JavaScript 对象(类型化) | User | 指定返回对象中包含哪些属性。 |
JavaScript 对象(普通) | { title: "Hello world" } | 使用 select 和 include 来确定返回哪些字段。 |
null | null | 未找到记录 |
备注
findFirst
在后台调用findMany
并接受相同的查询选项。- 在使用
findFirst
查询时传入负值的take
会反转列表的顺序。
示例
请参阅过滤条件和运算符,了解如何过滤结果的示例。
获取 name
为 Alice
的第一个 User
记录
const user = await prisma.user.findFirst({
where: { name: 'Alice' },
});
获取 title
以 A test
开头的第一个 Post
记录,使用 take
反转列表
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({});
async function main() {
const a = await prisma.post.create({
data: {
title: 'A test 1',
},
});
const b = await prisma.post.create({
data: {
title: 'A test 2',
},
});
const c = await prisma.post.findFirst({
where: {
title: {
startsWith: 'A test',
},
},
orderBy: {
title: 'asc',
},
take: -1, // Reverse the list
});
}
main();
findFirstOrThrow()
findFirstOrThrow()
以与 findFirst()
相同的方式检索单个数据记录。但是,如果查询未找到记录,它会抛出 PrismaClientKnownRequestError
。
请注意,在 Prisma v6 之前,它会抛出 NotFoundError: No User found error
。
findFirstOrThrow()
与 findFirst()
的区别如下
-
其返回类型不可为空。例如,
post.findFirst()
可以返回post
或null
,但post.findFirstOrThrow
总是返回post
。 -
它与
$transaction
API 中的顺序操作不兼容。如果查询返回PrismaClientKnownRequestError
,则 API 不会回滚调用数组中的任何操作。作为一种变通方法,您可以按如下方式将交互式事务与$transaction
API 一起使用prisma.$transaction(async (tx) => {
await tx.model.create({ data: { ... });
await tx.model.findFirstOrThrow();
})
findMany()
findMany
返回记录列表。
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
select | XOR<PostSelect, null> | 否 | 指定返回对象中包含哪些属性。 |
include | XOR<PostInclude, null> | 否 | 指定返回对象中应预加载哪些关系。 |
omit | XOR<PostOmit, null> | 否 | 指定返回对象中排除哪些属性。自 5.13.0 起在预览中。 |
relationLoadStrategy | 'join' 或 'query' | 否 | 默认:join 。指定关联查询的加载策略。仅与 include (或关联字段上的 select )结合使用时可用。自 5.9.0 起在预览中。 |
where | UserWhereInput | 否 | 将 所有 模型字段包装在类型中,以便列表可以通过任何属性进行过滤。 |
orderBy | XOR<Enumerable<PostOrder ByInput>, PostOrderByInput> | 否 | 允许您按任何属性对返回的列表进行排序。 |
cursor | UserWhereUniqueInput | 否 | 指定列表的位置(该值通常指定 id 或其他唯一值)。 |
take | number | 否 | 指定列表中应返回多少个对象(从列表的开头(正值)或结尾(负值)或从提及的 cursor 位置来看) |
skip | number | 否 | 指定列表中应跳过多少个返回对象。 |
distinct | Enumerable<UserDistinctFieldEnum> | 否 | 允许您按特定字段过滤掉重复行 - 例如,仅返回不同的 Post 标题。 |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
JavaScript 数组对象(类型化) | User[] | |
JavaScript 数组对象(普通) | [{ title: "Hello world" }] | 使用 select 和 include 来确定返回哪些字段。 |
空数组 | [] | 未找到匹配记录。 |
示例
请参阅过滤条件和运算符,了解如何过滤结果的示例。
获取所有 name
为 Alice
的 User
记录
const user = await prisma.user.findMany({
where: { name: 'Alice' },
});
create()
create
创建一个新的数据库记录。
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
data | XOR<UserCreateInput, UserUncheckedCreateInput> | 是 | 将所有模型字段包装在类型中,以便在创建新记录时可以提供这些字段。它还包括关系字段,允许执行(事务性)嵌套插入。在数据模型中标记为可选或具有默认值的字段是可选的。 |
select | XOR<UserSelect, null> | 否 | 指定返回对象中包含哪些属性。 |
include | XOR<UserInclude, null> | 否 | 指定返回对象中应预加载哪些关系。 |
omit | XOR<UserOmit, null> | 否 | 指定返回对象中排除哪些属性。自 5.13.0 起在预览中。 |
relationLoadStrategy | 'join' 或 'query' | 否 | 默认:join 。指定关联查询的加载策略。仅与 include (或关联字段上的 select )结合使用时可用。自 5.9.0 起在预览中。 |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
JavaScript 对象(类型化) | User | |
JavaScript 对象(普通) | { name: "Alice Wonderland" } | 使用 select 和 include 来确定返回哪些字段。 |
备注
- 您还可以执行嵌套的
create
- 例如,同时添加一个User
和两个Post
记录。
示例
创建一个只包含必需字段 email
的新记录
const user = await prisma.user.create({
data: { email: 'alice@prisma.io' },
});
创建多个新记录
在大多数情况下,您可以使用 createMany()
或 createManyAndReturn()
查询执行批量插入。但是,在某些场景下,create()
是插入多条记录的最佳选择。
以下示例会产生两条 INSERT
语句
import { Prisma, PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({ log: ['query'] });
async function main() {
let users: Prisma.UserCreateInput[] = [
{
email: 'ariana@prisma.io',
name: 'Ari',
profileViews: 20,
coinflips: [true, false, false],
role: 'ADMIN',
},
{
email: 'elsa@prisma.io',
name: 'Elsa',
profileViews: 20,
coinflips: [true, false, false],
role: 'ADMIN',
},
];
await Promise.all(
users.map(async (user) => {
await prisma.user.create({
data: user,
});
})
);
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});
prisma:query BEGIN
prisma:query INSERT INTO "public"."User" ("name","email","profileViews","role","coinflips") VALUES ($1,$2,$3,$4,$5) RETURNING "public"."User"."id"
prisma:query SELECT "public"."User"."id", "public"."User"."name", "public"."User"."email", "public"."User"."profileViews", "public"."User"."role", "public"."User"."coinflips" FROM "public"."User" WHERE "public"."User"."id" = $1 LIMIT $2 OFFSET $3
prisma:query INSERT INTO "public"."User" ("name","email","profileViews","role","coinflips") VALUES ($1,$2,$3,$4,$5) RETURNING "public"."User"."id"
prisma:query COMMIT
prisma:query SELECT "public"."User"."id", "public"."User"."name", "public"."User"."email", "public"."User"."profileViews", "public"."User"."role", "public"."User"."coinflips" FROM "public"."User" WHERE "public"."User"."id" = $1 LIMIT $2 OFFSET $3
prisma:query COMMIT
update()
update
更新现有的数据库记录。
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
data | XOR<UserUpdateInput UserUncheckedUpdateInput> | 是 | 将模型的所有字段包装在类型中,以便在更新现有记录时可以提供这些字段。在数据模型中标记为可选或具有默认值的字段是可选的。 |
where | UserWhereUniqueInput | 是 | 包装模型的所有字段,以便可以选择记录(了解更多)。 在版本 4.5.0 之前,此类型仅包装模型的 唯一 字段。 |
select | XOR<UserSelect, null> | 否 | 指定返回对象中包含哪些属性。 |
include | XOR<UserInclude, null> | 否 | 指定返回对象中应预加载哪些关系。 |
omit | XOR<UserOmit, null> | 否 | 指定返回对象中排除哪些属性。自 5.13.0 起在预览中。 |
relationLoadStrategy | 'join' 或 'query' | 否 | 默认:join 。指定关联查询的加载策略。仅与 include (或关联字段上的 select )结合使用时可用。自 5.9.0 起在预览中。 |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
JavaScript 对象(类型化) | User | |
JavaScript 对象(普通) | { name: "Alice Wonderland" } | 使用 select 和 include 来确定返回哪些字段。 |
RecordNotFound 异常 | 如果记录不存在,则抛出异常。 |
备注
示例
将 id
为 1
的 User
记录的 email
更新为 alice@prisma.io
const user = await prisma.user.update({
where: { id: 1 },
data: { email: 'alice@prisma.io' },
});
upsert()
本节介绍 upsert()
操作的用法。要了解如何在 update()
中使用嵌套 upsert 查询,请参考相关文档。
upsert
执行以下操作
- 如果现有数据库记录满足
where
条件,则更新该记录 - 如果没有数据库记录满足
where
条件,则创建新的数据库记录
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
create | XOR<UserCreateInput, UserUncheckedCreateInput> | 是 | 将模型的所有字段包装在类型中,以便在创建新记录时可以提供这些字段。它还包括关系字段,允许执行(事务性)嵌套插入。在数据模型中标记为可选或具有默认值的字段是可选的。 |
update | XOR<UserUpdateInput, UserUncheckedUpdateInput> | 是 | 将模型的所有字段包装在类型中,以便在更新现有记录时可以提供这些字段。在数据模型中标记为可选或具有默认值的字段是可选的。 |
where | UserWhereUniqueInput | 是 | 包装模型的所有字段,以便可以选择记录(了解更多)。 在版本 4.5.0 之前,此类型仅包装模型的 唯一 字段。 |
select | XOR<UserSelect, null> | 否 | 指定返回对象中包含哪些属性。 |
include | XOR<UserInclude, null> | 否 | 指定返回对象中应预加载哪些关系。 |
omit | XOR<UserOmit, null> | 否 | 指定返回对象中排除哪些属性。自 5.13.0 起在预览中。 |
relationLoadStrategy | 'join' 或 'query' | 否 | 默认:join 。指定关联查询的加载策略。仅与 include (或关联字段上的 select )结合使用时可用。自 5.9.0 起在预览中。 |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
JavaScript 对象(类型化) | User | |
JavaScript 对象(普通) | { name: "Alice Wonderland" } | 使用 select 和 include 来确定返回哪些字段。 |
备注
- 要在更新时执行算术运算(加、减、乘、除),请使用原子更新以防止竞态条件。
- 如果同时发生两个或更多 upsert 操作且记录尚不存在,则可能发生竞态条件。结果,一个或多个 upsert 操作可能会抛出唯一键约束错误。您的应用程序代码可以捕获此错误并重试该操作。了解更多。
- 从版本 4.6.0 开始,Prisma ORM 在可能的情况下将 upsert 查询交给数据库处理。了解更多。
示例
更新(如果存在)或创建 email
为 alice@prisma.io
的新 User
记录
const user = await prisma.user.upsert({
where: { id: 1 },
update: { email: 'alice@prisma.io' },
create: { email: 'alice@prisma.io' },
});
upsert 中的唯一键约束错误
问题
如果同时发生多个 upsert 操作且记录尚不存在,则一个或多个操作可能会返回唯一键约束错误。
原因
当 Prisma Client 执行 upsert 操作时,它首先检查该记录是否已存在于数据库中。为了进行此检查,Prisma Client 使用 upsert 操作中的 where
子句执行读取操作。这有两种可能的结果,如下所示
- 如果记录不存在,则 Prisma Client 创建该记录。
- 如果记录存在,则 Prisma Client 更新它。
当您的应用程序尝试执行两个或更多并发 upsert 操作时,可能发生竞态条件,即两个或更多操作找不到记录,因此尝试创建该记录。在这种情况下,其中一个操作成功创建了新记录,而其他操作失败并返回唯一键约束错误。
解决方案
在应用程序代码中处理 P2002 错误。发生此错误时,重试 upsert 操作以更新行。
数据库 upsert
在可能的情况下,Prisma Client 会将 upsert
查询交给数据库处理。这称为数据库 upsert。
数据库 upserts 具有以下优势
- 它们比 Prisma Client 处理的 upserts 更快
- 唯一键约束错误不会发生
当满足特定条件时,Prisma Client 会自动使用数据库 upsert。当这些条件不满足时,Prisma Client 会处理 upsert
。
为了使用数据库 upsert,Prisma Client 会向数据库发送 SQL 构造 INSERT ... ON CONFLICT SET .. WHERE
。
数据库 upsert 前提条件
如果您的技术栈满足以下条件,Prisma Client 可以使用数据库 upserts
- 您使用 Prisma ORM 4.6.0 或更高版本
- 您的应用程序使用 CockroachDB、PostgreSQL 或 SQLite 数据源
数据库 upsert 查询条件
当 upsert
查询满足以下条件时,Prisma Client 会使用数据库 upsert
upsert
的create
和update
选项中没有嵌套查询- 查询不包含使用嵌套读取的选择
- 查询只修改一个模型
upsert
的where
选项中只有一个唯一字段where
选项中的唯一字段和create
选项中的唯一字段具有相同的值
如果您的查询不满足这些条件,则 Prisma Client 会自行处理 upsert。
数据库 upsert 示例
以下示例使用此 schema
model User {
id Int @id
profileViews Int
userName String @unique
email String
@@unique([id, profileViews])
}
以下 upsert
查询满足所有条件,因此 Prisma Client 使用数据库 upsert。
prisma.user.upsert({
where: {
userName: 'Alice',
},
create: {
id: 1,
profileViews: 1,
userName: 'Alice',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});
在这种情况下,Prisma 使用以下 SQL 查询
INSERT INTO "public"."User" ("id","profileViews","userName","email") VALUES ($1,$2,$3,$4)
ON CONFLICT ("userName") DO UPDATE
SET "email" = $5 WHERE ("public"."User"."userName" = $6 AND 1=1) RETURNING "public"."User"."id", "public"."User"."profileViews", "public"."User"."userName", "public"."User"."email"
以下查询的 where
子句中包含多个唯一值,因此 Prisma Client 不使用数据库 upsert
prisma.User.upsert({
where: {
userName: 'Alice',
profileViews: 1,
id: 1,
},
create: {
id: 1,
profileViews: 1,
userName: 'Alice',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});
在以下查询中,where
和 create
选项中的 userName
值不同,因此 Prisma Client 不使用数据库 upsert。
prisma.User.upsert({
where: {
userName: 'Alice',
},
create: {
id: 1,
profileViews: 1,
userName: 'AliceS',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});
在以下查询中,对 posts
中 title
字段的选择是嵌套读取,因此 Prisma Client 不使用数据库 upsert。
prisma.user.upsert({
select: {
email: true,
id: true,
posts: {
select: {
title: true,
},
},
},
where: {
userName: 'Alice',
},
create: {
id: 1,
profileViews: 1,
userName: 'Alice',
email: 'alice@prisma.io',
},
update: {
email: 'updated@example.com',
},
});
delete()
delete
删除现有数据库记录。您可以删除记录
- 按 ID
- 按 唯一 属性
要删除符合特定条件的记录,请使用带过滤器的deleteMany
。
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
where | UserWhereUniqueInput | 是 | 包装模型的所有字段,以便可以选择记录(了解更多)。 在版本 4.5.0 之前,此类型仅包装模型的 唯一 字段。 |
select | XOR<UserSelect, null> | 否 | 指定返回对象中包含哪些属性。 |
include | XOR<UserInclude, null> | 否 | 指定返回对象中应预加载哪些关系。 |
omit | XOR<UserOmit, null> | 否 | 指定返回对象中排除哪些属性。自 5.13.0 起在预览中。 |
relationLoadStrategy | 'join' 或 'query' | 否 | 默认:join 。指定关联查询的加载策略。仅与 include (或关联字段上的 select )结合使用时可用。自 5.9.0 起在预览中。 |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
JavaScript 对象(类型化) | User | 已删除的 User 记录。 |
JavaScript 对象(普通) | { name: "Alice Wonderland" } | 已删除的 User 记录中的数据。使用 select 和 include 来确定要返回哪些字段。 |
RecordNotFound 异常 | 如果记录不存在,则抛出异常。 |
备注
- 要根据某些条件删除多个记录(例如,所有 email 地址为
prisma.io
的User
记录,使用deleteMany
)
示例
删除 id
为 1
的 User
记录
const user = await prisma.user.delete({
where: { id: 1 },
});
删除 email
等于 else@prisma.io
的 User
记录
以下查询删除特定的用户记录,并使用 select
返回已删除用户的 name
和 email
const deleteUser = await prisma.user.delete({
where: {
email: 'elsa@prisma.io',
},
select: {
email: true,
name: true,
},
});
{ "email": "elsa@prisma.io", "name": "Elsa" }
createMany()
createMany
在事务中创建多个记录。
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
data | Enumerable<UserCreateManyInput> | 是 | 将所有模型字段包装在一个类型中,以便在创建新记录时提供它们。数据模型中标记为可选或具有默认值的字段是可选的。 |
是否跳过重复项? | 布尔值 | 否 | 不要插入具有已存在的唯一字段或 ID 字段的记录。仅受支持 ON CONFLICT DO NOTHING 的数据库支持。这不包括 MongoDB 和 SQLServer |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
BatchPayload | { count: 3 } | 创建的记录数量计数。 |
备注
- 从 Prisma ORM 5.12.0 版本开始,SQLite 现在支持
createMany()
。 - MongoDB、SQLServer 或 SQLite 不支持
skipDuplicates
选项。 - 您无法在顶级
createMany()
查询中使用嵌套的create
、createMany
、connect
、connectOrCreate
查询来创建或连接关系。请参阅此处的变通方法。 - 您可以在
update()
或create()
查询中使用嵌套的createMany
查询 - 例如,同时添加一个User
和两个Post
记录,并带有嵌套的createMany
。
示例
创建多个新用户
const users = await prisma.user.createMany({
data: [
{ name: 'Sonali', email: 'sonali@prisma.io' },
{ name: 'Alex', email: 'alex@prisma.io' },
],
});
createManyAndReturn()
createManyAndReturn
创建多个记录并返回结果对象。
此功能在 Prisma ORM 5.14.0 及更高版本中可用于 PostgreSQL、CockroachDB 和 SQLite。
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
data | Enumerable<UserCreateManyInput> | 是 | 将所有模型字段包装在一个类型中,以便在创建新记录时提供它们。数据模型中标记为可选或具有默认值的字段是可选的。 |
select | XOR<UserSelect, null> | 否 | 指定要包含在返回对象中的属性。 |
omit | XOR<UserOmit, null> | 否 | 指定要从返回对象中排除的属性。自 5.13.0 起处于预览阶段。与 select 互斥。 |
include | XOR<UserInclude, null> | 否 | 指定应在返回对象上急切加载哪些关系。 |
是否跳过重复项? | 布尔值 | 否 | 不要插入具有已存在的唯一字段或 ID 字段的记录。仅受支持 ON CONFLICT DO NOTHING 的数据库支持。这不包括 MongoDB 和 SQLServer |
备注
- SQLite 不支持
skipDuplicates
选项。 - 请注意,
createManyAndReturn
返回的元素顺序不保证。 - 您无法在顶级
createManyAndReturn()
查询中使用嵌套的create
、createMany
、connect
、connectOrCreate
查询来创建或连接关系。请参阅此处的变通方法。 - 通过
include
包含关系时,每个关系都会生成一个单独的查询。 - 不支持
relationLoadStrategy: join
。
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
JavaScript 数组对象(类型化) | User[] | |
JavaScript 数组对象(普通) | [{ name: "Sonali" }] | 使用 select 、omit 和 include 来确定要返回哪些字段。 |
示例
创建并返回多个新用户
const users = await prisma.user.createManyAndReturn({
data: [
{ name: 'Sonali', email: 'sonali@prisma.io' },
{ name: 'Alex', email: 'alex@prisma.io' },
],
})
[
{ "id": 0, "name": "Sonali", "email": "sonali@prisma.io", "profileViews": 0 },
{ "id": 1, "name": "Alex", "email": "alex@prisma.io", "profileViews": 0 }
]
updateMany()
updateMany
批量更新现有数据库记录并返回更新的记录数量。
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
data | XOR<UserUpdateManyMutationInput, UserUncheckedUpdateManyInput> | 是 | 包装模型的所有字段,以便在更新现有记录时提供它们。数据模型中标记为可选或具有默认值的字段在 data 上是可选的。 |
where | UserWhereInput | 否 | 包装模型所有字段,以便可以按任何属性过滤列表。如果您不过滤列表,将更新所有记录。 |
limit | number | 否 | 限制要更新的记录数量。 |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
BatchPayload | { count: 4 } | 更新的记录计数。 |
export type BatchPayload = {
count: number;
};
示例
将所有 name
为 Alice
的 User
记录更新为 ALICE
const updatedUserCount = await prisma.user.updateMany({
where: { name: 'Alice' },
data: { name: 'ALICE' },
});
更新所有 email
包含 prisma.io
且至少一个相关 Post
赞数大于 10 的 User
记录
const updatedUserCount = await prisma.user.updateMany({
where: {
email: {
contains: 'prisma.io',
},
posts: {
some: {
likes: {
gt: 10,
},
},
},
},
data: {
role: 'USER',
},
});
更新 email
包含 prisma.io
的 User
记录,但仅限于更新 5 条记录。
const updatedUserCount = await prisma.user.updateMany({
where: {
email: {
contains: 'prisma.io',
},
},
data: {
role: 'USER',
},
limit: 5,
});
updateManyAndReturn()
此功能在 Prisma ORM 6.2.0 及更高版本中可用于 PostgreSQL、CockroachDB 和 SQLite。
updateManyAndReturn
更新多个记录并返回结果对象。
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
data | XOR<UserUpdateManyMutationInput, UserUncheckedUpdateManyInput> | 是 | 包装模型的所有字段,以便在更新现有记录时提供它们。数据模型中标记为可选或具有默认值的字段在 data 上是可选的。 |
where | UserWhereInput | 否 | 包装模型所有字段,以便可以按任何属性过滤列表。如果您不过滤列表,将更新所有记录。 |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
JavaScript 数组对象(类型化) | User[] | |
JavaScript 数组对象(普通) | [{ name: "Sonali" }] | 使用 select 、omit 和 include 来确定要返回哪些字段。 |
示例
更新并返回多个用户
const users = await prisma.user.updateManyAndReturn({
where: {
email: {
contains: 'prisma.io',
}
},
data: [
{ role: 'ADMIN' }
],
})
[
{ "id": 0, "name": "Sonali", "email": "sonali@prisma.io", "role": "ADMIN", "profileViews": 0 },
{ "id": 1, "name": "Alex", "email": "alex@prisma.io", "role": "ADMIN", "profileViews": 0 }
]
deleteMany()
deleteMany
在事务中删除多个记录。
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
where | UserWhereInput | 否 | 包装模型所有字段,以便可以按任何字段过滤列表。 |
limit | Int | 否 | 限制删除的记录数量。 |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
BatchPayload | { count: 4 } | 删除的记录计数。 |
export type BatchPayload = {
count: number;
};
示例
删除所有 User
记录
const deletedUserCount = await prisma.user.deleteMany({});
删除所有 name
为 Alice
的 User
记录
const deletedUserCount = await prisma.user.deleteMany({
where: { name: 'Alice' },
});
删除所有 email
包含 prisma.io
的 User
记录,但仅限于删除 5 条记录。
const deletedUserCount = await prisma.user.deleteMany({
where: {
email: {
contains: 'prisma.io',
},
},
limit: 5,
});
有关如何过滤要删除的记录的示例,请参阅过滤条件和运算符。
count()
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
where | UserWhereInput | 否 | 将 所有 模型字段包装在类型中,以便列表可以通过任何属性进行过滤。 |
orderBy | XOR<Enumerable<PostOrder ByInput>, PostOrderByInput> | 否 | 允许您按任何属性对返回的列表进行排序。 |
cursor | UserWhereUniqueInput | 否 | 指定列表的位置(该值通常指定 id 或其他唯一值)。 |
take | number | 否 | 指定列表中应返回多少个对象(从列表的开头(正值)或结尾(负值)或从提及的 cursor 位置来看) |
skip | number | 否 | 指定列表中应跳过多少个返回对象。 |
返回类型
返回类型 | 示例 | 描述 |
---|---|---|
number | 29 | 记录计数。 |
UserCountAggregateOutputType | { _all: 27, name: 10 } | 如果使用 select ,则返回。 |
示例
计算所有 User
记录数量
const result = await prisma.user.count();
计算所有至少有一个已发布 Post
的 User
记录数量
const result = await prisma.user.count({
where: {
post: {
some: {
published: true,
},
},
},
});
使用 select
执行三次单独计数
以下查询返回
- 所有记录的计数 (
_all
) - 所有具有非
null
name
字段的记录计数 - 所有具有非
null
city
字段的记录计数
const c = await prisma.user.count({
select: {
_all: true,
city: true,
name: true,
},
});
aggregate()
另请参阅:聚合、分组和汇总
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
where | UserWhereInput | 否 | 将 所有 模型字段包装在类型中,以便列表可以通过任何属性进行过滤。 |
orderBy | XOR<Enumerable<UserOrderByInput>, UserOrderByInput> | 否 | 允许您按任何属性对返回的列表进行排序。 |
cursor | UserWhereUniqueInput | 否 | 指定列表的位置(该值通常指定 id 或其他唯一值)。 |
take | number | 否 | 指定列表中应返回多少个对象(从列表的开头(正值)或结尾(负值)或从提及的 cursor 位置来看) |
skip | number | 否 | 指定列表中应跳过多少个返回对象。 |
_count | true | 否 | 返回匹配记录或非 null 字段的计数。 |
_avg | UserAvgAggregateInputType | 否 | 返回指定字段所有值的平均值。 |
_sum | UserSumAggregateInputType | 否 | 返回指定字段所有值的总和。 |
_min | UserMinAggregateInputType | 否 | 返回指定字段的最小可用值。 |
_max | UserMaxAggregateInputType | 否 | 返回指定字段的最大可用值。 |
示例
返回所有 User
记录 profileViews
的 _min
、_max
和 _count
const minMaxAge = await prisma.user.aggregate({
_count: {
_all: true,
},
_max: {
profileViews: true,
},
_min: {
profileViews: true,
},
});
返回所有 User
记录 profileViews
的 _sum
const setValue = await prisma.user.aggregate({
_sum: {
profileViews: true,
},
});
groupBy()
另请参阅:聚合、分组和汇总
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
where | UserWhereInput | 否 | 将 所有 模型字段包装在类型中,以便列表可以通过任何属性进行过滤。 |
orderBy | XOR<Enumerable<UserOrderByInput>, UserOrderByInput> | 否 | 允许您按 by 中也存在的任何属性对返回列表进行排序。 |
by | Array<UserScalarFieldEnum> | string | 否 | 指定用于分组记录的字段或字段组合。 |
having | UserScalarWhereWithAggregatesInput | 否 | 允许您按聚合值过滤组 - 例如,仅返回平均年龄小于 50 的组。 |
take | number | 否 | 指定列表中应返回多少个对象(从列表的开头(正值)或结尾(负值)或从提及的 cursor 位置来看) |
skip | number | 否 | 指定列表中应跳过多少个返回对象。 |
_count | true | UserCountAggregateInputType | 否 | 返回匹配记录或非 null 字段的计数。 |
_avg | UserAvgAggregateInputType | 否 | 返回指定字段所有值的平均值。 |
_sum | UserSumAggregateInputType | 否 | 返回指定字段所有值的总和。 |
_min | UserMinAggregateInputType | 否 | 返回指定字段的最小可用值。 |
_max | UserMaxAggregateInputType | 否 | 返回指定字段的最大可用值。 |
示例
按 country
/city
分组,其中平均 profileViews
大于 200
,并返回每组 profileViews
的 _sum
该查询还返回每组中 _all
记录的计数,以及每组中所有具有非 null
city
字段值的记录。
const groupUsers = await prisma.user.groupBy({
by: ['country', 'city'],
_count: {
_all: true,
city: true,
},
_sum: {
profileViews: true,
},
orderBy: {
country: 'desc',
},
having: {
profileViews: {
_avg: {
gt: 200,
},
},
},
});
[
{
country: 'Denmark',
city: 'Copenhagen',
_sum: { profileViews: 490 },
_count: {
_all: 70,
city: 8,
},
},
{
country: 'Sweden',
city: 'Stockholm',
_sum: { profileViews: 500 },
_count: {
_all: 50,
city: 3,
},
},
];
findRaw()
请参阅:使用原始 SQL (findRaw()
)。
aggregateRaw()
请参阅:使用原始 SQL (aggregateRaw()
)。
模型查询选项
select
select
定义了 Prisma Client 返回的对象中包含哪些字段。请参阅:选择字段和包含关系。
备注
- 您不能在同一级别上组合使用
select
和include
。 - 在 3.0.1 及更高版本中,您可以选择关系的
_count
。
示例
选择单个 User
记录的 name
和 profileViews
字段
const result = await prisma.user.findUnique({
where: { id: 1 },
select: {
name: true,
profileViews: true,
},
});
选择多个 User
记录的 email
和 role
字段
const result = await prisma.user.findMany({
select: {
email: true,
role: true,
},
});
选择关系的 _count
const usersWithCount = await prisma.user.findMany({
select: {
_count: {
select: { posts: true },
},
},
});
选择相关 Post
记录的 'id' 和 'title' 字段
const result = await prisma.user.findMany({
select: {
id: true,
name: true,
posts: {
select: {
id: true,
title: true,
},
},
},
});
select
内的 include
const result = await prisma.user.findMany({
select: {
id: true,
name: true,
posts: {
include: {
author: true,
},
},
},
});
为 select
生成的类型
以下示例演示了如何将validator
与 select
一起使用
const selectNameEmailNotPosts = Prisma.validator<Prisma.UserSelect>()({
name: true,
email: true,
posts: false,
});
include
include
定义了 Prisma Client 返回的结果中包含哪些关系。请参阅:选择字段和包含关系。
备注
- 在 3.0.1 及更高版本中,您可以
include
关系的_count
示例
加载 User
记录时包含 posts
和 profile
关系
const users = await prisma.user.findMany({
include: {
posts: true, // Returns all fields for all posts
profile: true, // Returns all Profile fields
},
});
创建新的 User
记录并带有两条 Post
记录时,在返回的对象中包含 posts
关系
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
posts: {
create: [{ title: 'This is my first post' }, { title: 'Here comes a second post' }],
},
},
include: { posts: true }, // Returns all fields for all posts
});
为 include
生成的类型
以下示例演示了如何将validator
与 include
一起使用
const includePosts = Prisma.validator<Prisma.UserInclude>()({
posts: true,
});
包含关系的 _count
const usersWithCount = await prisma.user.findMany({
include: {
_count: {
select: { posts: true },
},
},
});
omit
omit
定义了从 Prisma Client 返回的对象中排除哪些字段。
备注
- 您不能组合使用
omit
和select
,因为它们的用途相反 omit
在 Prisma ORM 6.2.0 中正式发布。在 Prisma ORM5.13.0
到6.1.0
版本中,它通过omitApi
预览功能提供。
示例
从所有 User
记录中忽略 password
字段
const result = await prisma.user.findMany({
omit: {
password: true,
},
});
从所有 User
的 posts
关系中忽略 title
字段
const results = await prisma.user.findMany({
omit: {
password: true,
},
include: {
posts: {
omit: {
title: true,
},
},
},
});
为 omit
生成的类型
以下示例演示了如何将validator
与 omit
一起使用
const omitPassword = Prisma.validator<Prisma.UserOmit>()({
password: true,
});
relationLoadStrategy
(预览)
relationLoadStrategy
指定了应如何从数据库加载关系。它有两个可能的值
join
(默认):使用数据库级别的LATERAL JOIN
(PostgreSQL) 或相关子查询 (MySQL),通过对数据库的一次查询获取所有数据。query
:向数据库发送多个查询(每表一个),并在应用程序级别进行连接。
注意:一旦
relationLoadStrategy
从预览阶段进入正式可用阶段,join
将普遍成为所有关系查询的默认设置。
您可以在此处了解更多关于连接策略的信息。
由于 relationLoadStrategy
选项目前处于预览阶段,您需要在 Prisma schema 文件中通过 relationJoins
预览功能标志来启用它
generator client {
provider = "prisma-client-js"
previewFeatures = ["relationJoins"]
}
添加此标志后,您需要再次运行 prisma generate
来重新生成 Prisma Client。relationJoins
功能目前在 PostgreSQL、CockroachDB 和 MySQL 上可用。
备注
- 在大多数情况下,默认的
join
策略会更有效。如果您想节省数据库服务器资源,或者性能分析显示应用程序级别的连接性能更好,请使用query
。 - 您只能在查询的顶层指定
relationLoadStrategy
。顶层选择将影响所有嵌套子查询。
示例
使用 include
时通过数据库级 JOIN 加载 posts
关系
const users = await prisma.user.findMany({
relationLoadStrategy: 'join',
include: {
posts: true,
},
});
使用 select
时通过数据库级 JOIN 加载 posts
关系
const users = await prisma.user.findMany({
relationLoadStrategy: 'join',
select: {
posts: true,
},
});
where
where
定义了一个或多个过滤器,可用于根据记录属性(如用户的电子邮件地址)或相关记录属性(如用户最近 10 篇帖子的标题)进行过滤。
示例
const results = await prisma.user.findMany({
where: {
email: {
endsWith: 'prisma.io',
},
},
});
为 where
生成的类型
以下示例演示了如何将validator
与 where
一起使用
-
UserWhereInput
// UserWhereInput
const whereNameIs = Prisma.validator<Prisma.UserWhereInput>()({
name: 'Rich',
});
// It can be combined with conditional operators too
const whereNameIs = Prisma.validator<Prisma.UserWhereInput>()({
name: 'Rich',
AND: [
{
email: {
contains: 'rich@boop.com',
},
},
],
}); -
UserWhereUniqueInput
此类型通过公开模型上的任何唯一字段来工作。分配了@id
的字段被视为唯一字段,分配了@unique
的字段也如此。从 4.5.0 版本开始,此类型公开模型上的所有字段。这意味着当您根据唯一字段过滤单个记录时,您可以同时检查其他非唯一和唯一字段。了解更多。
// UserWhereUniqueInput
const whereEmailIsUnique = Prisma.validator<Prisma.UserWhereUniqueInput>()({
email: 'rich@boop.com',
}) -
PostScalarWhereInput
const whereScalarTitleIs = Prisma.validator<Prisma.PostScalarWhereInput>()({
title: 'boop',
}); -
PostUpdateWithWhereUniqueWithoutAuthorInput
- 此类型接受唯一的where
字段(@id
或其他分配的@unique
),并更新Post
模型上除Author
之外的任何字段。Author
是Post
模型上的标量字段。const updatePostByIdWithoutAuthor =
Prisma.validator<Prisma.PostUpdateWithWhereUniqueWithoutAuthorInput>()({
where: {
id: 1,
},
data: {
content: 'This is some updated content',
published: true,
title: 'This is a new title',
},
}); -
PostUpsertWithWhereUniqueWithoutAuthorInput
- 如果 id 匹配,此类型将更新Post
记录的 title 字段;如果不存在,则会创建它。const updatePostTitleOrCreateIfNotExist =
Prisma.validator<Prisma.PostUpsertWithWhereUniqueWithoutAuthorInput>()({
where: {
id: 1,
},
update: {
title: 'This is a new title',
},
create: {
id: 1,
title: 'If the title doesnt exist, then create one with this text',
},
}); -
PostUpdateManyWithWhereWithoutAuthorInput
- 此类型将更新所有 published 设置为 false 的Post
记录。const publishAllPosts = Prisma.validator<Prisma.PostUpdateManyWithWhereWithoutAuthorInput>()({
where: {
published: {
equals: false,
},
},
data: {
published: true,
},
});
orderBy
对记录列表进行排序。另请参阅:排序
备注
-
在 4.1.0 及更高版本中,您可以将
null
记录排在前面或后面。有关详细信息,请参阅将 null 排在前面或后面排序。
sort
参数的输入
名称 | 描述 |
---|---|
asc | 升序排序 (A → Z) |
desc | 降序排序 (Z → A) |
nulls
参数的输入
注意
- 此参数是可选的。
- 仅适用于可选的标量字段。如果您尝试在必填字段或关系字段上按 null 排序,Prisma Client 会抛出 P2009 错误。
- 该功能在 4.1.0 及更高版本中作为预览功能提供。有关如何启用该功能的详细信息,请参阅将 null 排在前面或后面排序。
名称 | 描述 |
---|---|
first | 将 null 值排在前面排序。 |
last | 将 null 值排在后面排序。 |
示例
按 email
字段对 User
排序
以下示例返回按 email
升序排序的所有 User
记录
const users = await prisma.user.findMany({
orderBy: {
email: 'asc',
},
});
以下示例返回按 email
降序排序的所有 User
记录
const users = await prisma.user.findMany({
orderBy: {
email: 'desc',
},
});
按相关 User
记录的 name
对 Post
排序
以下查询按用户姓名对帖子排序
const posts = await prisma.post.findMany({
orderBy: {
author: {
name: 'asc',
},
},
});
按相关 User
记录的 name
对 Post
排序,将 null
记录排在前面
以下查询按用户姓名对帖子排序,将 null
记录排在前面
const posts = await prisma.post.findMany({
orderBy: {
author: {
name: { sort: 'asc', nulls: 'first' },
},
},
});
按标题相关性对 Post
排序
对于 PostgreSQL,此功能仍处于预览阶段。请启用 fullTextSearchPostgres
功能标志才能使用它。
以下查询按搜索词 'database'
与标题的相关性对帖子排序
const posts = await prisma.post.findMany({
orderBy: {
_relevance: {
fields: ['title'],
search: 'database',
sort: 'asc'
},
})
按 posts
计数排序 User
以下查询按帖子计数对用户进行排序
const getActiveusers = await prisma.user.findMany({
orderBy: {
posts: {
count: 'desc',
},
},
});
按多个字段排序 User
- email
和 role
以下示例按两个字段对用户进行排序 - 首先是 email
,然后是 role
const users = await prisma.user.findMany({
select: {
email: true,
role: true,
},
orderBy: [
{
email: 'desc',
},
{
role: 'desc',
},
],
});
排序参数的顺序很重要 - 以下查询先按 role
排序,然后按 email
排序。注意结果的区别
const users = await prisma.user.findMany({
select: {
email: true,
role: true,
},
orderBy: [
{
role: 'desc',
},
{
email: 'desc',
},
],
});
按 email
排序 User
,选择 name
和 email
以下示例返回所有 User
记录的 name
和 email
字段,按 email
排序
const users3 = await prisma.user.findMany({
orderBy: {
email: 'asc',
},
select: {
name: true,
email: true,
},
});
按 email
排序 User
记录,并按 title
排序嵌套的 Post
记录
以下示例
- 返回按
email
排序的所有User
记录 - 对于每个
User
记录,返回按title
排序的所有嵌套Post
记录的title
字段
const usersWithPosts = await prisma.user.findMany({
orderBy: {
email: 'asc',
},
include: {
posts: {
select: {
title: true,
},
orderBy: {
title: 'asc',
},
},
},
});
排序一个用户的嵌套 Post
记录列表
以下示例通过 ID 检索单个 User
记录,以及按 title
排序的嵌套 Post
记录列表
const userWithPosts = await prisma.user.findUnique({
where: {
id: 1,
},
include: {
posts: {
orderBy: {
title: 'desc',
},
select: {
title: true,
published: true,
},
},
},
});
按 enum
排序
以下示例按 role
(一个 enum
)对所有 User
记录进行排序
const sort = await prisma.user.findMany({
orderBy: {
role: 'desc',
},
select: {
email: true,
role: true,
},
});
生成的 orderBy
类型
以下示例演示了如何将 validator
与 orderBy
一起使用
UserOrderByInput
const orderEmailsByDescending = Prisma.validator<Prisma.UserOrderByInput>()({
email: 'desc',
});
distinct
从 findMany
或 findFirst
的记录列表中去重。另请参见:聚合、分组和汇总
示例
在单个字段上选择去重
以下示例返回所有不同的 city
字段,并且只选择 city
和 country
字段
const distinctCities = await prisma.user.findMany({
select: {
city: true,
country: true,
},
distinct: ['city'],
});
[
{ city: 'Paris', country: 'France' },
{ city: 'Lyon', country: 'France' },
];
在多个字段上选择去重
以下示例返回所有不同的 city
和 country
字段组合,并且只选择 city
和 country
字段
const distinctCitiesAndCountries = await prisma.user.findMany({
select: {
city: true,
country: true,
},
distinct: ['city', 'country'],
});
[
{ city: 'Paris', country: 'France' },
{ city: 'Paris', country: 'Denmark' },
{ city: 'Lyon', country: 'France' },
];
请注意,现在除了 "Paris, France" 之外,还有一个 "Paris, Denmark"
结合过滤器选择去重
以下示例返回用户电子邮件包含 "prisma.io"
的所有不同的 city
和 country
字段组合,并且只选择 city
和 country
字段
const distinctCitiesAndCountries = await prisma.user.findMany({
where: {
email: {
contains: 'prisma.io',
},
},
select: {
city: true,
country: true,
},
distinct: ['city', 'country'],
});
nativeDistinct
在 Prisma schema 中启用 nativeDistinct
会将 distinct
操作推送到数据库层(如果支持)。这可以显著提高性能。但是,请注意:
- 某些数据库可能不完全支持在特定字段组合上使用 DISTINCT。
- 不同提供商的行为可能不同。
要启用 nativeDistinct
generator client {
provider = "prisma-client-js"
previewFeatures = ["nativeDistinct"]
}
有关更多详细信息,请参阅预览功能。
嵌套查询
create
嵌套的 create
查询向父记录添加新的相关记录或记录集。参见:使用关联
备注
- 当您
create()
(prisma.user.create(...)
)新的父记录或update()
(prisma.user.update(...)
)现有父记录时,create
可用作嵌套查询。 - 您可以使用嵌套的
create
或嵌套的createMany
来创建多个相关记录。如果您需要skipDuplicates
查询选项,应使用createMany
。
示例
创建新的 User
记录和新的 Profile
记录
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
profile: {
create: { bio: 'Hello World' },
},
},
});
创建新的 Profile
记录和新的 User
记录
const user = await prisma.profile.create({
data: {
bio: 'Hello World',
user: {
create: { email: 'alice@prisma.io' },
},
},
})
创建新的 User
记录和新的 Post
记录
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
posts: {
create: { title: 'Hello World' },
},
},
});
创建新的 User
记录和两个新的 Post
记录
由于是一对多关系,您还可以通过向 create
传递一个数组来一次创建多个 Post
记录
const user = await prisma.user.create({
data: {
email: 'alice@prisma.io',
posts: {
create: [
{
title: 'This is my first post',
},
{
title: 'Here comes a second post',
},
],
},
},
});
注意:您也可以使用嵌套的 createMany
来达到相同的效果。
通过创建新的 Profile
记录来更新现有 User
记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
create: { bio: 'Hello World' },
},
},
});
通过创建新的 Post
记录来更新现有 User
记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
create: { title: 'Hello World' },
},
},
})
createMany
嵌套的 createMany
查询向父记录添加一组新的记录。参见:使用关联
备注
- 当您
create()
(prisma.user.create(...)
)新的父记录或update()
(prisma.user.update(...)
)现有父记录时,createMany
可用作嵌套查询。- 在一对多关系的上下文中可用 — 例如,您可以
prisma.user.create(...)
创建一个用户,并使用嵌套的createMany
创建多个帖子(帖子有一个用户)。 - 在多对多关系的上下文中**不可用** — 例如,您**不能**
prisma.post.create(...)
创建一个帖子并使用嵌套的createMany
创建类别(多个帖子有多个类别)。
- 在一对多关系的上下文中可用 — 例如,您可以
- 您不能嵌套额外的
create
或createMany
。 - 允许直接设置外键 — 例如,在帖子中设置
categoryId
。 - 自 Prisma ORM 5.12.0 版本起,SQLite 支持嵌套的
createMany
。 - 您可以使用嵌套的
create
或嵌套的createMany
来创建多个相关记录 — 如果您不需要skipDuplicates
查询选项,您可能应该使用create
。
选项
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
data | Enumerable<UserCreateManyInput> | 是 | 将所有模型字段包装在一个类型中,以便在创建新记录时提供它们。数据模型中标记为可选或具有默认值的字段是可选的。 |
是否跳过重复项? | 布尔值 | 否 | 不要插入具有已存在的唯一字段或 ID 字段的记录。仅受支持 ON CONFLICT DO NOTHING 的数据库支持。这不包括 MongoDB 和 SQLServer |
示例
更新 User
以及多个新的相关 Post
记录
const user = await prisma.user.update({
where: {
id: 9,
},
data: {
name: 'Elliott',
posts: {
createMany: {
data: [{ title: 'My first post' }, { title: 'My second post' }],
},
},
},
});
set
set
会覆盖关联的值 - 例如,用不同的列表替换 Post
记录列表。参见:使用关联
示例
更新现有 User
记录,断开所有之前的 Post
记录连接,并连接两个其他现有记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
set: [{ id: 32 }, { id: 42 }],
},
},
});
connect
嵌套的 connect
查询通过指定 ID 或唯一标识符将记录连接到现有相关记录。参见:使用关联
备注
-
当您创建新的父记录或更新现有父记录时,
connect
可用作嵌套查询。 -
如果相关记录不存在,Prisma Client 将抛出异常
The required connected records were not found. Expected 1 records to be connected, found 0.
-
同时使用
set
和connect
时,它们的应用顺序会显著影响结果。如果在connect
之前使用set
,连接的记录将只反映connect
操作建立的最终状态,因为set
会在connect
建立新连接之前清除所有现有连接。相反,如果在set
之前应用connect
,set
操作将通过清除所有已连接的记录并用其自己指定的状体替换它们来覆盖connect
操作。
示例
创建新的 Profile
记录,并通过唯一字段将其连接到现有 User
记录
const user = await prisma.profile.create({
data: {
bio: 'Hello World',
user: {
connect: { email: 'alice@prisma.io' },
},
},
});
创建新的 Profile
记录,并通过 ID 字段将其连接到现有 User
记录
const user = await prisma.profile.create({
data: {
bio: 'Hello World',
user: {
connect: { id: 42 }, // sets userId of Profile record
},
},
});
在 2.11.0 及更高版本中,您可以直接设置外键
const user = await prisma.profile.create({
data: {
bio: 'Hello World',
userId: 42,
},
});
但是,您不能在同一个查询中同时使用直接方法和 connect
方法。详情请参见 此问题评论。
创建新的 Post
记录并将其连接到现有 User
记录
const user = await prisma.post.create({
data: {
title: 'Hello World',
author: {
connect: { email: 'alice@prisma.io' },
},
},
});
通过连接到现有 Profile
记录来更新现有 User
记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
connect: { id: 24 },
},
},
});
通过连接到两个现有 Post
记录来更新现有 User
记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
connect: [{ id: 24 }, { id: 42 }],
},
},
});
connectOrCreate
connectOrCreate
要么通过 ID 或唯一标识符将记录连接到现有相关记录,要么在记录不存在时创建新的相关记录。参见:使用关联
备注
-
多个**并发事务**中运行的
connectOrCreate
查询可能导致**竞态条件**。考虑以下示例,其中两个查询试图同时connectOrCreate
一个名为computing
的博客文章标签(标签名称必须唯一)- 查询 A
- 查询 B
const createPost = await prisma.post.create({
data: {
title: 'How to create a compiler',
content: '...',
author: {
connect: {
id: 9,
},
},
tags: {
connectOrCreate: {
create: {
name: 'computing',
},
where: {
name: 'computing',
},
},
},
},
})const createPost = await prisma.post.create({
data: {
title: 'How to handle schema drift in production',
content: '...',
author: {
connect: {
id: 15,
},
},
tags: {
connectOrCreate: {
create: {
name: 'computing',
},
where: {
name: 'computing',
},
},
},
},
})如果查询 A 和查询 B 以以下方式重叠,查询 A 将导致异常
查询 A(失败 ❌) 查询 B(成功 ✅) 查询到达服务器,启动事务 A 查询到达服务器,启动事务 B 查找 tagName
等于computing
的记录,未找到记录查找 tagName
等于computing
的记录,未找到记录创建 tagName
等于computing
的记录并连接创建 tagName
等于computing
的记录唯一性冲突,记录已被事务 B 创建 为了解决这种情况,我们建议捕获唯一性冲突异常(
PrismaClientKnownRequestError
,错误代码P2002
)并重试失败的查询。
示例
创建新的 Profile
记录,然后将其连接到现有 User
记录,或创建新的 User
以下示例
- 创建一个
Profile
- 尝试将配置文件连接到电子邮件地址为
alice@prisma.io
的User
- 如果不存在匹配的用户,则创建新用户
const user = await prisma.profile.create({
data: {
bio: 'The coolest Alice on the planet',
user: {
connectOrCreate: {
where: { email: 'alice@prisma.io' },
create: { email: 'alice@prisma.io'}
},
},
})
创建新的 Post
记录并将其连接到现有 User
记录,或创建新的 User
const user = await prisma.post.create({
data: {
title: 'Hello World',
author: {
connectOrCreate: {
where: { email: 'alice@prisma.io' },
create: { email: 'alice@prisma.io' },
},
},
},
});
通过连接到现有 Profile
记录,或创建新的 Profile
记录来更新现有 User
记录
以下示例
- 尝试将用户连接到
id
为20
的Profile
- 如果不存在匹配的配置文件,则创建新的配置文件
const updateUser = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
connectOrCreate: {
where: { id: 20 },
create: {
bio: 'The coolest Alice in town',
},
},
},
},
});
通过连接到两个现有 Post
记录,或创建两个新的 Post
记录来更新现有 User
记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
connectOrCreate: [
{
where: { id: 32 },
create: { title: 'This is my first post' },
},
{
where: { id: 19 },
create: { title: 'This is my second post' },
},
],
},
},
});
disconnect
嵌套的 disconnect
查询断开父记录和相关记录之间的连接,但不删除任何一条记录。参见:使用关联
备注
-
disconnect
仅在关联是可选时可用。 -
如果您尝试断开的关联不存在
-
(在 2.21.0 及更高版本中),该操作不执行任何操作
-
(在 2.21.0 之前),如果提供的 ID 或唯一标识符未连接,Prisma Client 会抛出异常
The records for relation `PostToUser` between the `User` and `Post` models are not connected.
-
示例
通过断开与其连接的 Profile
记录来更新现有 User
记录
const user = await prisma.user.update({
where: { email: 'bob@prisma.io' },
data: {
profile: {
disconnect: true,
},
},
});
通过断开与其连接的两个 Post
记录来更新现有 User
记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
disconnect: [{ id: 44 }, { id: 46 }],
},
},
});
update
嵌套的 update
查询更新一个或多个父记录 ID 为 n
的相关记录。参见:使用关联
备注
-
嵌套的
update
查询仅在顶级update
查询(例如,prisma.user.update(...)
)的上下文中可用。 -
如果父记录不存在,Prisma Client 将抛出异常
AssertionError("Expected a valid parent ID to be present for nested update to-one case.")
-
如果您要更新的相关记录不存在,Prisma Client 将抛出异常
AssertionError("Expected a valid parent ID to be present for nested update to-one case.")
示例
通过更新与其连接的 Profile
记录来更新现有 User
记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
update: { bio: 'Hello World' },
},
},
});
通过更新与其连接的两个 Post
记录来更新现有 User
记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
update: [
{
data: { published: true },
where: { id: 32 },
},
{
data: { published: true },
where: { id: 23 },
},
],
},
},
});
upsert
本节介绍在 update()
中使用嵌套的 upsert。要了解 upsert()
操作,请参考链接的文档。
嵌套的 upsert
查询如果相关记录存在则更新,否则创建新的相关记录。
示例
通过更新与其连接的 Profile
记录或创建新的记录来更新现有 User
记录 (upsert)
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
upsert: {
create: { bio: 'Hello World' },
update: { bio: 'Hello World' },
},
},
},
});
通过更新与其连接的两个 Post
记录或创建新的记录来更新现有 User
记录 (upsert)
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
upsert: [
{
create: { title: 'This is my first post' },
update: { title: 'This is my first post' },
where: { id: 32 },
},
{
create: { title: 'This is my second post' },
update: { title: 'This is my second post' },
where: { id: 23 },
},
],
},
},
});
delete
嵌套的 delete
查询删除相关记录。父记录不会被删除。
备注
delete
仅在关联是可选时可用。
示例
通过删除与其连接的 Profile
记录来更新现有 User
记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
profile: {
delete: true,
},
},
});
通过删除与其连接的两个 Post
记录来更新现有 User
记录
const user = await prisma.user.update({
where: { email: 'alice@prisma.io' },
data: {
posts: {
delete: [{ id: 34 }, { id: 36 }],
},
},
});
updateMany
嵌套的 updateMany
更新相关记录列表并支持过滤 - 例如,您可以更新用户的未发布帖子。
示例
更新属于特定用户的所有未发布帖子
const result = await prisma.user.update({
where: {
id: 2,
},
data: {
posts: {
updateMany: {
where: {
published: false,
},
data: {
likes: 0,
},
},
},
},
});
deleteMany
嵌套的 deleteMany
删除相关记录并支持过滤。例如,您可以在更新用户其他属性的同时删除用户的帖子。
示例
在更新中删除属于特定用户的所有帖子
const result = await prisma.user.update({
where: {
id: 2,
},
data: {
name: 'Updated name',
posts: {
deleteMany: {},
},
},
});
筛选条件和运算符
equals
值等于 n
。
示例
返回所有 name
等于 "Eleanor"
的用户
const result = await prisma.user.findMany({
where: {
name: {
equals: 'Eleanor',
},
},
});
您也可以省略 equals
const result = await prisma.user.findMany({
where: {
name: 'Eleanor',
},
});
返回所有数量低于“警告数量”阈值的产品
此示例比较同一模型的字段,该功能自 4.3.0 版本开始提供。
const productsWithLowQuantity = await prisma.product.findMany({
where: {
quantity: {
lte: prisma.product.fields.warnQuantity
},
},
});
返回所有喜欢蓝色和绿色的用户
此示例查找将 favoriteColors
字段设置为 ['blue', 'green']
的用户。
请注意,使用 equals
时,元素的顺序很重要。也就是说,['blue', 'green']
与 ['green', 'blue']
**不**相等
const favoriteColorFriends = await prisma.user.findMany({
where: {
favoriteColors: {
equals: ['blue', 'green'],
},
},
});
not
值不等于 n
。
示例
返回所有 name
**不**等于 "Eleanor"
的用户
const result = await prisma.user.findMany({
where: {
name: {
not: 'Eleanor',
},
},
});
not
将返回所有与给定值不匹配的项目。但是,如果列是可空(nullable)的,则不会返回 NULL
值。如果您需要返回 null 值,请使用 OR
运算符来包含 NULL
值。
返回所有 name
**不**等于 "Eleanor"
的用户,**包括** name
为 NULL
的用户
await prisma.user.findMany({
where: {
OR: [
{ name: { not: 'Eleanor' } },
{ name: null }
]
}
})
in
值 n
存在于列表中。
不会返回 null
值。例如,如果您将 in
和 NOT
结合使用以返回名称**不在**列表中的用户,则不会返回名称为 null
值的用户。
示例
获取 id
存在于以下列表中的 User
记录:[22, 91, 14, 2, 5]
const getUser = await prisma.user.findMany({
where: {
id: { in: [22, 91, 14, 2, 5] },
},
});
获取 name
存在于以下列表中的 User
记录:['Saqui', 'Clementine', 'Bob']
const getUser = await prisma.user.findMany({
where: {
name: { in: ['Saqui', 'Clementine', 'Bob'] },
},
});
获取 name
**不在**列表中的 User
记录
以下示例结合了 in
和 NOT
。您也可以使用 notIn
。
const getUser = await prisma.user.findMany({
where: {
NOT: {
name: { in: ['Saqui', 'Clementine', 'Bob'] },
},
},
});
获取至少有一篇 Post
拥有至少一个指定 Category
的 User
记录
const getUser = await prisma.user.findMany({
where: {
// Find users where..
posts: {
some: {
// ..at least one (some) posts..
categories: {
some: {
// .. have at least one category ..
name: {
in: ['Food', 'Introductions'], // .. with a name that matches one of the following.
},
},
},
},
},
},
});
notIn
值 n
不存在于列表中。
备注
- 不会返回
null
值。
示例
获取 id
**不**存在于以下列表中的 User
记录:[22, 91, 14, 2, 5]
const getUser = await prisma.user.findMany({
where: {
id: { notIn: [22, 91, 14, 2, 5] },
},
});
lt
值 n
小于 x
。
示例
获取所有 likes
小于 9
的 Post
记录
const getPosts = await prisma.post.findMany({
where: {
likes: {
lt: 9,
},
},
});
lte
值 n
小于或等于 x
。
示例
获取所有 likes
小于或等于 9
的 Post
记录
const getPosts = await prisma.post.findMany({
where: {
likes: {
lte: 9,
},
},
});
gt
值 n
大于 x
。
示例
获取所有 likes
大于 9
的 Post
记录
const getPosts = await prisma.post.findMany({
where: {
likes: {
gt: 9,
},
},
});
gte
值 n
大于或等于 x
。
示例
获取所有 likes
大于或等于 9
的 Post
记录
const getPosts = await prisma.post.findMany({
where: {
likes: {
gte: 9,
},
},
});
示例
获取所有 date_created
晚于 2020 年 3 月 19 日的 Post
记录
const result = await prisma.post.findMany({
where: {
date_created: {
gte: new Date('2020-03-19T14:21:00+0200') /* Includes time offset for UTC */,
},
},
});
contains
值 n
包含 x
。
示例
计数所有 content
包含 databases
的 Post
记录
const result = await prisma.post.count({
where: {
content: {
contains: 'databases',
},
},
});
计数所有 content
**不**包含 databases
的 Post
记录
const result = await prisma.post.count({
where: {
NOT: {
content: {
contains: 'databases',
},
},
},
});
search
使用全文搜索在 String
字段中搜索。
对于 PostgreSQL,此功能仍处于预览阶段。请启用 fullTextSearchPostgres
功能标志才能使用它。
示例
查找所有标题包含 cat
或 dog
的文章。
const result = await prisma.post.findMany({
where: {
title: {
search: 'cat | dog',
},
},
});
查找所有标题包含 cat
和 dog
的文章。
const result = await prisma.post.findMany({
where: {
title: {
search: 'cat & dog',
},
},
});
查找所有标题不包含 cat
的文章。
const result = await prisma.post.findMany({
where: {
title: {
search: '!cat',
},
},
});
mode
备注
- 仅由 PostgreSQL 和 MongoDB 连接器支持
示例
获取所有 Post
记录,其中 title
不区分大小写地包含 prisma
const result = await prisma.post.findMany({
where: {
title: {
contains: 'prisma',
mode: 'insensitive',
},
},
});
startsWith
示例
获取所有 Post
记录,其中 title
以 Pr
开头(例如 Prisma
)
const result = await prisma.post.findMany({
where: {
title: {
startsWith: 'Pr',
},
},
});
endsWith
获取所有 User
记录,其中 email
以 prisma.io
结尾
const result = await prisma.user.findMany({
where: {
email: {
endsWith: 'prisma.io',
},
},
});
AND
所有条件必须返回 true
。或者,可以将对象列表传递到 where
子句中 - 无需 AND
运算符。
示例
获取所有 Post
记录,其中 content
字段包含 Prisma
且 published
为 false
const result = await prisma.post.findMany({
where: {
AND: [
{
content: {
contains: 'Prisma',
},
},
{
published: {
equals: false,
},
},
],
},
});
获取所有 Post
记录,其中 content
字段包含 Prisma
且 published
为 false
(无 AND
)
以下格式返回与上一个示例相同的结果,但不使用 AND
运算符
const result = await prisma.post.findMany({
where: {
content: {
contains: 'Prisma',
},
published: {
equals: false,
},
},
});
获取所有 Post
记录,其中 title
字段包含 Prisma
或 databases
,且 published
为 false
以下示例结合了 OR
和 AND
const result = await prisma.post.findMany({
where: {
OR: [
{
title: {
contains: 'Prisma',
},
},
{
title: {
contains: 'databases',
},
},
],
AND: {
published: false,
},
},
});
OR
一个或多个条件必须返回 true
。
示例
获取所有 Post
记录,其中 title
字段包含 Prisma
或 databases
const result = await prisma.post.findMany({
where: {
OR: [
{
title: {
contains: 'Prisma',
},
},
{
title: {
contains: 'databases',
},
},
],
},
});
获取所有 Post
记录,其中 title
字段包含 Prisma
或 databases
,但不包含 SQL
以下示例结合了 OR
和 NOT
const result = await prisma.post.findMany({
where: {
OR: [
{
title: {
contains: 'Prisma',
},
},
{
title: {
contains: 'databases',
},
},
],
NOT: {
title: {
contains: 'SQL',
},
},
},
});
获取所有 Post
记录,其中 title
字段包含 Prisma
或 databases
,且 published
为 false
以下示例结合了 OR
和 AND
const result = await prisma.post.findMany({
where: {
OR: [
{
title: {
contains: 'Prisma',
},
},
{
title: {
contains: 'databases',
},
},
],
AND: {
published: false,
},
},
});
NOT
所有条件必须返回 false
。
示例
获取所有 Post
记录,其中 title
不包含 SQL
const result = await prisma.post.findMany({
where: {
NOT: {
title: {
contains: 'SQL',
},
},
},
});
获取所有 Post
记录,其中 title
字段包含 Prisma
或 databases
,但不包含 SQL
,且关联的 User
记录的电子邮件地址不包含 sarah
const result = await prisma.post.findMany({
where: {
OR: [
{
title: {
contains: 'Prisma',
},
},
{
title: {
contains: 'databases',
},
},
],
NOT: {
title: {
contains: 'SQL',
},
},
user: {
NOT: {
email: {
contains: 'sarah',
},
},
},
},
include: {
user: true,
},
});
关联过滤
some
返回所有记录,其中一个或多个(“some”)关联记录匹配过滤条件。
备注
- 可以在不带参数的情况下使用
some
来返回所有至少存在一个关联的记录
示例
获取所有 User
记录,其中部分文章提及了 Prisma
const result = await prisma.user.findMany({
where: {
post: {
some: {
content: {
contains: "Prisma"
}
}
}
}
}
every
返回所有记录,其中所有(“every”)关联记录都匹配过滤条件。
示例
获取所有 User
记录,其中所有文章都已发布
const result = await prisma.user.findMany({
where: {
post: {
every: {
published: true
},
}
}
}
none
返回所有记录,其中零个关联记录匹配过滤条件。
备注
- 可以在不带参数的情况下使用
none
来返回所有没有关联的记录
示例
获取所有没有文章的 User
记录
const result = await prisma.user.findMany({
where: {
post: {
none: {} // User has no posts
}
}
}
获取所有没有已发布文章的 User
记录
const result = await prisma.user.findMany({
where: {
post: {
none: {
published: true
}
}
}
}
is
返回所有关联记录匹配过滤条件的记录(例如,用户的名字 is
Bob)。
示例
获取所有 Post
记录,其中用户的名字是 "Bob"
const result = await prisma.post.findMany({
where: {
user: {
is: {
name: "Bob"
},
}
}
}
isNot
返回所有关联记录不匹配过滤条件的记录(例如,用户的名字 isNot
Bob)。
示例
获取所有 Post
记录,其中用户的名字不是 "Bob"
const result = await prisma.post.findMany({
where: {
user: {
isNot: {
name: "Bob"
},
}
}
}
标量列表方法
set
使用 set
覆盖标量列表字段的值。
备注
-
set
是可选的 - 您可以直接设置值tags: ['computers', 'books'];
示例
将 tags
的值设置为字符串值列表
const setTags = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
set: ['computing', 'books'],
},
},
});
将 tags
设置为值列表,不使用 set
关键字
const setTags = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: ['computing', 'books'],
},
});
将 tags
的值设置为单个字符串值
const setTags = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
set: 'computing',
},
},
});
push
push
可在 2.20.0 及更高版本中使用。使用 push
向标量列表字段添加一个或多个值。
备注
示例
将 computing
项添加到 tags
列表中
const addTag = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
push: 'computing',
},
},
});
const addTag = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
push: ['computing', 'genetics'],
},
},
});
unset
使用 unset
来取消设置标量列表的值。与 set: null
不同,unset
会完全移除该列表。
示例
取消设置 tags
的值
const setTags = await prisma.post.update({
where: {
id: 9,
},
data: {
tags: {
unset: true,
},
},
});
标量列表过滤器
标量列表过滤器允许您按列表/数组字段的内容进行过滤。
备注
has
指定的值存在于列表中。
示例
以下查询返回所有 Post
记录,其中 tags
列表包含 "databases"
const posts = await client.post.findMany({
where: {
tags: {
has: 'databases',
},
},
});
以下查询返回所有 Post
记录,其中 tags
列表不包含 "databases"
const posts = await client.post.findMany({
where: {
NOT: {
tags: {
has: 'databases',
},
},
},
});
hasEvery
列表中的每个值都存在。
示例
以下查询返回所有 Post
记录,其中 tags
列表至少包含 "databases"
和 "typescript"
const posts = await prisma.post.findMany({
where: {
tags: {
hasEvery: ['databases', 'typescript'],
},
},
});
hasSome
列表中至少存在一个值。
示例
以下查询返回所有 Post
记录,其中 tags
列表包含 "databases"
或 "typescript"
const posts = await prisma.post.findMany({
where: {
tags: {
hasSome: ['databases', 'typescript'],
},
},
});
isEmpty
列表为空。
示例
以下查询返回所有没有标签的 Post
记录
const posts = await prisma.post.findMany({
where: {
tags: {
isEmpty: true,
},
},
});
isSet
过滤列表,仅包含已设置(设置为某个值,或显式设置为 null
)的结果。将此过滤器设置为 true
将排除未设置的 undefined 结果。
示例
以下查询返回所有 Post
记录,其中 tags
已被设置为 null
或某个值
const posts = await prisma.post.findMany({
where: {
tags: {
isSet: true,
},
},
});
equals
列表完全匹配指定的值。
示例
以下查询返回所有 Post
记录,其中 tags
列表仅包含 "databases"
和 "typescript"
const posts = await prisma.post.findMany({
where: {
tags: {
equals: ['databases', 'typescript'],
},
},
});
复合类型方法
仅在 Prisma 3.10.0
及更高版本的 MongoDB 中可用。
set
使用 set
覆盖复合类型的值。
备注
set
关键字是可选的 - 您可以直接设置值photos: [
{ height: 100, width: 200, url: '1.jpg' },
{ height: 100, width: 200, url: '2.jpg' },
];
示例
在新 order
中设置 shippingAddress
复合类型
const order = await prisma.order.create({
data: {
// Normal relation
product: { connect: { id: 'some-object-id' } },
color: 'Red',
size: 'Large',
// Composite type
shippingAddress: {
set: {
street: '1084 Candycane Lane',
city: 'Silverlake',
zip: '84323',
},
},
},
});
将可选复合类型设置为 null
const order = await prisma.order.create({
data: {
// Embedded optional type, set to null
billingAddress: {
set: null,
},
},
});
unset
使用 unset
来取消设置复合类型的值。与 set: null
不同,这会从 MongoDB 文档中完全移除该字段。
示例
从 order
中移除 billingAddress
const order = await prisma.order.update({
where: {
id: 'some-object-id',
},
data: {
billingAddress: {
// Unset the billing address
// Removes "billingAddress" field from order
unset: true,
},
},
});
update
使用 update
更新必填复合类型中的字段。
备注
示例
更新 shippingAddress
复合类型的 zip 字段
const order = await prisma.order.update({
where: {
id: 'some-object-id',
},
data: {
shippingAddress: {
// Update just the zip field
update: {
zip: '41232',
},
},
},
});
upsert
使用 upsert
更新现有的可选复合类型(如果存在),否则设置该复合类型。
备注
示例
如果 billingAddress
不存在则创建新地址,否则更新该地址
const order = await prisma.order.update({
where: {
id: 'some-object-id',
},
data: {
billingAddress: {
// Create the address if it doesn't exist,
// otherwise update it
upsert: {
set: {
street: '1084 Candycane Lane',
city: 'Silverlake',
zip: '84323',
},
update: {
zip: '84323',
},
},
},
},
});
push
使用 push
将值添加到复合类型列表的末尾。
示例
向 photos
列表中添加一张新照片
const product = prisma.product.update({
where: {
id: 10,
},
data: {
photos: {
// Push a photo to the end of the photos list
push: [{ height: 100, width: 200, url: '1.jpg' }],
},
},
});
复合类型过滤器
仅在 Prisma 3.11.0
及更高版本的 MongoDB 中可用。
equals
使用 equals
通过匹配复合类型或复合类型列表来过滤结果。要求复合类型的所有必填字段都匹配。
备注
匹配可选字段时,您需要区分文档中未定义(缺失)的字段和已明确设置为 null
的字段
- 如果省略可选字段,它将匹配未定义的字段,但不匹配已设置为
null
的字段 - 如果使用
equals: { ... exampleField: null ... }
过滤可选字段的null
值,则它将仅匹配字段已设置为null
的文档,而不匹配未定义的字段
使用 equals
时,字段和列表的顺序很重要
- 对于字段,
{ "a": "1", "b": "2" }
和{ "b": "2", "a": "1" }
不被视为相等 - 对于列表,
[ { "a": 1 }, { "a": 2 } ]
和[ { "a": 2 }, { "a": 1 } ]
不被视为相等
示例
查找与给定 shippingAddress
完全匹配的订单
const orders = await prisma.order.findMany({
where: {
shippingAddress: {
equals: {
street: '555 Candy Cane Lane',
city: 'Wonderland',
zip: '52337',
},
},
},
});
查找包含照片且照片与一组 url
完全匹配的产品
const product = prisma.product.findMany({
where: {
equals: {
photos: [{ url: '1.jpg' }, { url: '2.jpg' }],
},
},
});
is
使用 is
通过匹配复合类型中的特定字段来过滤结果。
示例
查找 shippingAddress
匹配给定街道名称的订单
const orders = await prisma.order.findMany({
where: {
shippingAddress: {
is: {
street: '555 Candy Cane Lane',
},
},
},
});
isNot
使用 isNot
过滤不匹配的复合类型字段的结果。
示例
查找 shippingAddress
不匹配给定邮政编码的订单
const orders = await prisma.order.findMany({
where: {
shippingAddress: {
isNot: {
zip: '52337',
},
},
},
});
isEmpty
使用 isEmpty
过滤复合类型空列表的结果。
示例
查找没有照片的产品
const product = prisma.product.findMany({
where: {
photos: {
isEmpty: true,
},
},
});
every
使用 every
过滤复合类型列表,其中列表中的每个项目都匹配条件
示例
查找第一件产品,其中每张照片的 height
都为 200
const product = await prisma.product.findFirst({
where: {
photos: {
every: {
height: 200,
}
}
},
})
some
使用 some
过滤复合类型列表,其中列表中的一个或多个项目匹配条件。
示例
查找第一件产品,其中一张或多张照片的 url
为 2.jpg
const product = await prisma.product.findFirst({
where: {
photos: {
some: {
url: "2.jpg",
}
}
},
})
none
使用 none
过滤复合类型列表,其中列表中没有项目匹配条件。
示例
查找第一件产品,其中没有照片的 url
为 2.jpg
const product = await prisma.product.findFirst({
where: {
photos: {
none: {
url: "2.jpg",
}
}
},
})
原子数字操作
更新时的原子操作适用于数字字段类型(Float
和 Int
)。此功能允许您根据字段的当前值更新字段(例如减去或除以),而不会面临竞态条件的风险。
概述:竞态条件
操作符
选项 | 描述 |
---|---|
increment | 将n 添加到当前值。 |
decrement | 从当前值减去n 。 |
multiply | 将当前值乘以n 。 |
divide | 将当前值除以n 。 |
set | 设置当前字段值。与{ myField : n } 相同。 |
备注
- 每个查询每个字段只能执行一次原子更新。
- 如果字段为
null
,则不会被increment
、decrement
、multiply
或divide
更新。
示例
将所有Post
记录的view
和likes
字段全部增加1
const updatePosts = await prisma.post.updateMany({
data: {
views: {
increment: 1,
},
likes: {
increment: 1,
},
},
});
将所有Post
记录的views
字段全部设置为0
const updatePosts = await prisma.post.updateMany({
data: {
views: {
set: 0,
},
},
});
也可以写成
const updatePosts = await prisma.post.updateMany({
data: {
views: 0,
},
});
Json
过滤器
有关用例和高级示例,请参阅:使用Json
字段。
PostgreSQL和MySQL支持,path
选项的语法不同。PostgreSQL不支持对数组中的对象键值进行过滤。
本节示例假定pet
字段的值为
{
"favorites": {
"catBreed": "Turkish van",
"dogBreed": "Rottweiler",
"sanctuaries": ["RSPCA", "Alley Cat Allies"],
"treats": [
{ "name": "Dreamies", "manufacturer": "Mars Inc" },
{ "name": "Treatos", "manufacturer": "The Dog People" }
]
},
"fostered": {
"cats": ["Bob", "Alice", "Svetlana the Magnificent", "Queenie"]
},
"owned": {
"cats": ["Elliott"]
}
}
备注
Json
过滤的实现因数据库连接器而异- 过滤在PostgreSQL中区分大小写,且尚不支持
mode
path
path
表示特定键的位置。以下查询返回所有嵌套favourites
> dogBreed
键等于"Rottweiler"
的用户。
- PostgreSQL
- MySQL
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['favorites', 'dogBreed'],
equals: 'Rottweiler',
},
},
});
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.favorites.dogBreed',
equals: 'Rottweiler',
},
},
});
以下查询返回所有嵌套owned
> cats
数组包含"Elliott"
的用户。
- PostgreSQL
- MySQL
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['owned', 'cats'],
array_contains: ['Elliott'],
},
},
});
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.owned.cats',
array_contains: 'Elliott',
},
},
});
仅MySQL连接器支持按数组内部对象的键值进行过滤(如下所示)。
以下查询返回所有嵌套favorites
> treats
数组包含一个对象(其中name
值为"Dreamies"
)的用户。
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.favorites.treats[*].name',
array_contains: 'Dreamies',
},
},
});
string_contains
以下查询返回所有嵌套favorites
> catBreed
键值包含"Van"
的用户。
- PostgreSQL
- MySQL
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['favorites', 'catBreed'],
string_contains: 'Van',
},
},
});
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.favorites.catBreed',
string_contains: 'Van',
},
},
});
string_starts_with
以下查询返回所有嵌套favorites
> catBreed
键值以"Turkish"
开头的用户。
- PostgreSQL
- MySQL
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['favorites', 'catBreed'],
string_starts_with: 'Turkish',
},
},
});
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.favorites.catBreed',
string_starts_with: 'Turkish',
},
},
});
string_ends_with
以下查询返回所有嵌套favorites
> catBreed
键值以"Van"
结尾的用户。
- PostgreSQL
- MySQL
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['favorites', 'catBreed'],
string_ends_with: 'Van',
},
},
});
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.favorites.catBreed',
string_ends_with: 'Van',
},
},
});
mode
指定字符串过滤是否区分大小写(默认)或不区分大小写。
以下查询返回所有嵌套favorites
> catBreed
键值包含"Van"
或"van"
的用户。
- PostgreSQL
- MySQL
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['favorites', 'catBreed'],
string_contains: 'Van',
mode: "insensitive",
},
},
});
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.favorites.catBreed',
string_contains: 'Van',
mode: "insensitive",
},
},
});
array_contains
以下查询返回所有sanctuaries
数组包含值"RSPCA"
的用户。
- PostgreSQL
- MySQL
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['sanctuaries'],
array_contains: ['RSPCA'],
},
},
});
注意:在PostgreSQL中,array_contains
的值必须是一个数组而不是字符串,即使该数组只包含一个值。
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.sanctuaries',
array_contains: 'RSPCA',
},
},
});
以下查询返回所有sanctuaries
数组包含给定数组中所有值的用户。
- PostgreSQL
- MySQL
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['sanctuaries'],
array_contains: ['RSPCA', 'Alley Cat Allies'],
},
},
});
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.sanctuaries',
array_contains: ['RSPCA', 'Alley Cat Allies'],
},
},
});
array_starts_with
以下查询返回所有sanctuaries
数组以值"RSPCA"
开头的用户。
- PostgreSQL
- MySQL
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['sanctuaries'],
array_starts_with: 'RSPCA',
},
},
});
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.sanctuaries',
array_starts_with: 'RSPCA',
},
},
});
array_ends_with
以下查询返回所有sanctuaries
数组以值"Alley Cat Allies"
结尾的用户。
- PostgreSQL
- MySQL
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: ['sanctuaries'],
array_ends_with: 'Alley Cat Allies',
},
},
});
const getUsers = await prisma.user.findMany({
where: {
pets: {
path: '$.sanctuaries',
array_ends_with: 'Alley Cat Allies',
},
},
});
客户端方法
注意:客户端级别的方法以$
开头。
备注
- 使用
$extends
扩展的客户端实例上不存在$on
和$use
客户端方法。
$disconnect()
$disconnect()
方法关闭调用$connect
时建立的数据库连接,并停止运行Prisma ORM查询引擎的进程。有关$connect()
和$disconnect()
的概述,请参阅连接管理。
备注
$disconnect()
返回一个Promise
,所以应该在async
函数内部使用await
关键字调用它。
$connect()
$connect()
方法通过Prisma ORM的查询引擎建立与数据库的物理连接。有关$connect()
和$disconnect()
的概述,请参阅连接管理。
备注
$connect()
返回一个Promise
,所以应该在async
函数内部使用await
关键字调用它。
$on()
$on
在扩展客户端中不可用。请迁移到客户端扩展或在扩展客户端之前使用$on
方法。
$use()
$use()
方法添加中间件
prisma.$use(async (params, next) => {
console.log('This is middleware!');
// Modify or interrogate params here
return next(params);
});
next
next
代表中间件堆栈中的“下一层”,根据你在堆栈中的位置,它可能是下一个中间件或Prisma查询。
params
params
是一个对象,包含可在中间件中使用信息。
参数 | 描述 |
---|---|
action | 查询类型 - 例如,create 或findMany 。 |
args | 传递给查询的参数 - 例如,where 、data 或orderBy |
dataPath | 如果使用流畅API,则会填充。 |
model | 模型类型 - 例如,Post 或User 。 |
runInTransaction | 如果查询在事务上下文中运行,则返回true 。 |
如果需要将model
属性作为字符串,请使用:String(params.model)
参数示例值
{
args: { where: { id: 15 } },
dataPath: [ 'select', 'author', 'select', 'posts' ],
runInTransaction: false,
action: 'findMany',
model: 'Post'
}
示例
请参阅中间件示例。
$queryRawTyped
$queryRaw
请参阅:使用原生SQL ($queryRaw
)。
$queryRawUnsafe()
请参阅:使用原生SQL ($queryRawUnsafe()
)。
$executeRaw
$executeRawUnsafe()
请参阅:使用原生SQL ($executeRawUnsafe()
)。
$runCommandRaw()
请参阅:使用原生SQL ($runCommandRaw()
)。
$transaction()
请参阅:事务。
$metrics
Prisma Client指标为您提供了Prisma Client如何与数据库交互的详细洞察。您可以使用此洞察帮助诊断应用程序的性能问题。了解更多:指标。
Prisma Client指标有以下方法
$metrics.json()
:以JSON格式检索Prisma Client指标。$metrics.prometheus()
:以Prometheus格式检索Prisma Client指标。
$extends
通过$extends
,您可以创建和使用Prisma Client扩展,以下列方式向Prisma Client添加功能
model
:向模型添加自定义方法client
:向客户端添加自定义方法query
:创建自定义Prisma Client查询result
:向查询结果添加自定义字段
了解更多:Prisma Client扩展。
工具类型
工具类型是位于Prisma
命名空间下的辅助函数和类型。它们对于保证应用程序的类型安全非常有用。
Prisma.validator
validator
帮助您基于schema模型创建可重用的查询参数,同时确保创建的对象有效。另请参阅:使用Prisma.validator
使用validator
有两种方式
使用生成的Prisma Client类型
使用类型提供了一种类型级别的数据验证方法
Prisma.validator<GeneratedType>({ args });
使用“选择器”
使用选择器模式时,您使用现有的Prisma Client实例来创建validator。此模式允许您选择要验证的模型、操作和查询选项。
您还可以使用通过Prisma Client扩展进行扩展的Prisma Client实例。
Prisma.validator(PrismaClientInstance, '<model>', '<operation>', '<query option>')({ args });
示例
以下示例展示了如何提取和验证可在应用程序中重用的create
操作的输入
import { Prisma } from '@prisma/client';
const validateUserAndPostInput = (name, email, postTitle) => {
return Prisma.validator<Prisma.UserCreateInput>()({
name,
email,
posts: {
create: {
title: postTitle,
},
},
});
};
这是相同操作的另一种语法
import { Prisma } from '@prisma/client';
import prisma from './prisma';
const validateUserAndPostInput = (name, email, postTitle) => {
return Prisma.validator(
prisma,
'user',
'create',
'data'
)({
name,
email,
posts: {
create: {
title: postTitle,
},
},
});
};
比较同一表中的列
对于非唯一过滤器,您可以直接比较同一表中的列。
此功能在版本5.0.0中已正式可用,并在Prisma ORM 4.3.0至4.16.2版本中通过fieldReference
预览功能提供。
在以下情况下,必须使用原生查询来比较同一表中的列
- 如果使用早于4.3.0的版本
- 如果想使用唯一过滤器,例如
findUnique
或findUniqueOrThrow
- 如果想比较具有唯一约束的字段
- 如果想使用以下操作符之一将MySQL或MariaDB中的JSON字段与另一个字段进行比较:
gt
、gte
、lt
或lte
。请注意,您可以使用这些操作符将JSON字段与标量值进行比较。此限制仅在尝试将JSON字段与另一个字段进行比较时适用。
要比较同一表中的列,请使用<model>.fields
属性。在以下示例中,查询返回所有prisma.product.quantity
字段中的值小于或等于prisma.product.warnQuantity
字段中的值的记录。
prisma.product.findMany({
where: { quantity: { lte: prisma.product.fields.warnQuantity } },
});
fields
是每个模型的特殊属性。它包含该模型的字段列表。
注意事项
字段必须类型相同
只能比较相同类型的字段。例如,以下会导致错误
await prisma.order.findMany({
where: {
id: { equals: prisma.order.fields.due },
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Type error: id is a string, while amountDue is an integer
},
});
字段必须在同一模型中
只能使用fields
属性对同一模型中的字段进行比较。以下示例无效
await prisma.order.findMany({
where: {
id: { equals: prisma.user.fields.name },
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Type error: name is a field on the User model, not Order
},
});
但是,可以使用标准查询比较不同模型中的字段。
在groupBy
模型查询中,将引用字段放在by
参数中
如果使用带有having
选项的groupBy模型查询,则必须将引用字段放在by
参数中。
以下示例有效
prisma.user.groupBy({
by: ['id', 'name'],
having: { id: { equals: prisma.user.fields.name } },
});
以下示例无效,因为name
不在by
参数中
prisma.user.groupBy({
by: ['id'],
having: { id: { equals: prisma.user.fields.name } },
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// name is not in the 'by' argument
});
在标量列表中搜索字段
如果数据源支持标量列表(例如PostgreSQL),则可以搜索特定字段在字段列表中的所有记录。为此,请使用in
和notIn
过滤器引用标量列表。例如
await prisma.user.findMany({
where: {
// find all users where 'name' is in a list of tags
name: { in: prisma.user.fields.tags },
},
});
使用UserWhereUniqueInput
过滤非唯一字段
从版本5.0.0开始,where
上生成的类型UserWhereUniqueInput
暴露了模型上的所有字段,而不仅仅是唯一字段。在版本4.5.0到4.16.2之间,此功能可在extendedWhereUnique
预览标志下使用。
必须在where
语句中布尔操作符之外指定至少一个唯一字段,并且可以指定任意数量的其他唯一和非唯一字段。您可以使用此功能向返回单条记录的任何操作添加过滤器。例如,您可以将此功能用于以下方面
从版本4.6.0开始,您可以使用此功能过滤可选的一对一嵌套读取。
更新上的乐观并发控制
您可以使用非唯一字段过滤对update
操作执行乐观并发控制。
为了执行乐观并发控制,建议使用version
字段检查记录或相关记录中的数据在代码执行期间是否发生变化。在4.5.0版本之前,无法在update
操作中评估version
字段,因为该字段是非唯一的。从4.5.0版本开始,您可以评估version
字段。
在以下示例中,updateOne
和updateTwo
首先读取同一记录,然后尝试更新。数据库仅在version
中的值与初次读取时的值相同时才执行这些更新。当数据库执行这些更新中的第一个(可能是updateOne
或updateTwo
,取决于时机)时,它会增加version
中的值。这意味着数据库不会执行第二个更新,因为version
中的值已发生变化。
model User {
id Int @id @default(autoincrement())
email String @unique
city String
version Int
}
function updateOne() {
const user = await prisma.user.findUnique({ id: 1 });
await prisma.user.update({
where: { id: user.id, version: user.version },
data: { city: 'Berlin', version: { increment: 1 } },
});
}
function updateTwo() {
const user = await prisma.user.findUnique({ id: 1 });
await prisma.user.update({
where: { id: user.id, version: user.version },
data: { city: 'New York', version: { increment: 1 } },
});
}
function main() {
await Promise.allSettled([updateOne(), updateTwo()]);
}
权限检查
您可以使用非唯一字段过滤在更新期间检查权限。
在以下示例中,用户想要更新帖子标题。where
语句检查authorId
中的值以确认用户是帖子的作者。应用程序仅在用户是帖子作者时才更新帖子标题。
await prisma.post.update({
where: { id: 1, authorId: 1 },
data: { title: 'Updated post title' },
});
软删除
您可以使用非唯一字段过滤处理软删除。
在以下示例中,如果帖子被软删除,我们不希望返回该帖子。仅当isDeleted
中的值为false
时,操作才会返回该帖子。
prisma.Post.findUnique({ where: { id: postId, isDeleted: false } });
UserWhereUniqueInput
注意事项
UserWhereUniqueInput
与布尔操作符
使用UserWhereUniqueInput
时,必须在布尔操作符AND
、OR
、NOT
之外指定至少一个唯一字段。您仍然可以将这些布尔操作符与过滤器中的任何其他唯一字段或非唯一字段结合使用。
在以下示例中,我们测试了唯一字段id
以及email
。这是有效的。
await prisma.user.update({
where: { id: 1, OR: [{ email: "bob@prisma.io" }, { email: "alice@prisma.io" }] },
// ^^^ Valid: the expression specifies a unique field (`id`) outside of any boolean operators
data: { ... }
})
// SQL equivalent:
// WHERE id = 1 AND (email = "bob@prisma.io" OR email = "alice@prisma.io")
以下示例无效,因为在任何布尔操作符之外没有唯一字段
await prisma.user.update({
where: { OR: [{ email: "bob@prisma.io" }, { email: "alice@prisma.io" }] },
// ^^^ Invalid: the expressions does not contain a unique field outside of boolean operators
data: { ... }
})
一对一关系
从版本4.5.0开始,您可以在一对一关系的以下操作中过滤非唯一字段
- 嵌套更新
- 嵌套 upsert
- 嵌套 disconnect
- 嵌套删除
Prisma Client自动使用唯一过滤器选择相应的相关记录。因此,在使用WhereUniqueInput
生成的类型时,不需要在where
语句中指定唯一过滤器。相反,where
语句具有WhereInput
生成的类型。您可以使用此类型进行过滤,而无需受WhereUniqueInput
的限制。
嵌套更新示例
await prisma.user.update({
where: { id: 1, },
data: {
to_one: {
// Before Prisma version 4.5.0
update: { field: "updated" }
// From Prisma version 4.5.0, you can also do the following:
update: { where: { /*WhereInput*/ }, data: { field: "updated" } } }
}
}
})
嵌套 upsert 示例
await prisma.user.update({
where: { id: 1, },
data: {
to_one: {
upsert: {
where: { /* WhereInput */ } // new argument from Prisma 4.5.0
create: { /* CreateInput */ },
update: { /* CreateInput */ },
}
}
}
})
嵌套 disconnect 示例
await prisma.user.update({
where: { id: 1, },
data: {
to_one: {
// Before Prisma version 4.5.0
disconnect: true
// From Prisma version 4.5.0, you can also do the following:
disconnect: { /* WhereInput */ }
}
}
})
嵌套删除示例
await prisma.user.update({
where: { id: 1, },
data: {
to_one: {
// Before Prisma version 4.5.0
delete: true
// From Prisma version 4.5.0, you can also do the following:
delete: { /* WhereInput */ }
}
}
})
PrismaPromise
行为
所有Prisma Client查询都返回一个PrismaPromise
实例。这是一个“thenable”,意味着PrismaPromise
仅在您调用await
、.then()
或.catch()
时执行。这种行为与普通的JavaScript Promise
不同,后者立即开始执行。
例如
const findPostOperation = prisma.post.findMany({}); // Query not yet executed
findPostOperation.then(); // Prisma Client now executes the query
// or
await findPostOperation; // Prisma Client now executes the query
使用$transaction
API时,这种行为使得Prisma Client能够将所有查询作为一个事务传递给查询引擎。