跳到主要内容

原始查询

警告

使用 Prisma ORM 5.19.0,我们发布了 TypedSQL。TypedSQL 是一种编写类型安全且更易于添加到工作流程中的 SQL 查询的新方法。

我们强烈建议尽可能使用 TypedSQL 查询,而不是下面介绍的旧版原始查询。

Prisma 客户端支持将原始查询发送到您的数据库的选项。如果您希望在以下情况下使用原始查询

  • 您想运行高度优化的查询
  • 您需要 Prisma 客户端尚不支持的功能(请 考虑提出问题)

所有 Prisma ORM 支持的关系数据库都提供原始查询。此外,从版本 3.9.0 开始,MongoDB 中支持原始查询。有关更多详细信息,请参阅相关部分

使用关系数据库的原始查询

对于关系数据库,Prisma 客户端公开四种方法,允许您发送原始查询。您可以使用

  • $queryRaw 返回实际记录(例如,使用 SELECT)。
  • $executeRaw 返回受影响行的计数(例如,在 UPDATEDELETE 之后)。
  • $queryRawUnsafe 使用原始字符串返回实际记录(例如,使用 SELECT)。
  • $executeRawUnsafe 使用原始字符串返回受影响行的计数(例如,在 UPDATEDELETE 之后)。

名称中包含“Unsafe”的方法更加灵活,但 存在使您的代码容易受到 SQL 注入攻击的重大风险

其他两种方法可以使用简单的模板标签、不进行字符串构建和不进行连接来安全使用。但是,对于更复杂的使用场景,需要谨慎,因为在某些情况下使用这些方法仍然有可能引入 SQL 注入。有关更多详细信息,请参阅下面的 SQL 注入预防 部分。

注意:上面列表中的所有方法一次只能运行 一个 查询。您无法追加第二个查询 - 例如,使用 select 1; select 2; 调用任何一个方法将无法正常工作。

$queryRaw

$queryRaw 返回实际的数据库记录。例如,以下 SELECT 查询返回 User 表中每个记录的所有字段

const result = await prisma.$queryRaw`SELECT * FROM User`

该方法实现为 带标签的模板,允许您传递一个模板字面量,您可以在其中轻松插入您的 变量。反过来,Prisma 客户端会创建针对 SQL 注入安全的准备好的语句

const email = '[email protected]'
const result = await prisma.$queryRaw`SELECT * FROM User WHERE email = ${email}`

您也可以使用 Prisma.sql 帮助程序,实际上,$queryRaw 方法 只接受 模板字符串或 Prisma.sql 帮助程序

const email = '[email protected]'
const result = await prisma.$queryRaw(
Prisma.sql`SELECT * FROM User WHERE email = ${email}`
)
警告

如果您使用字符串构建将不受信任的输入合并到传递给此方法的查询中,那么您就会面临 SQL 注入攻击的可能性。SQL 注入攻击可能会使您的数据暴露于修改或删除。首选机制是在运行此方法时包含查询文本。有关此风险以及如何防止它的示例,请参阅下面的 SQL 注入预防 部分。

注意事项

请注意

  • 模板变量不能在 SQL 字符串字面量内使用。例如,以下查询 将无法 正常工作

    const name = 'Bob'
    await prisma.$queryRaw`SELECT 'My name is ${name}';`

    相反,您可以将整个字符串作为变量传递,或者使用字符串连接

    const name = 'My name is Bob'
    await prisma.$queryRaw`SELECT ${name};`
    const name = 'Bob'
    await prisma.$queryRaw`SELECT 'My name is ' || ${name};`
  • 模板变量只能用于数据值(如上面的示例中的 email)。变量不能用于标识符,例如列名、表名或数据库名,也不能用于 SQL 关键字。例如,以下两个查询 将无法 正常工作

    const myTable = 'user'
    await prisma.$queryRaw`SELECT * FROM ${myTable};`
    const ordering = 'desc'
    await prisma.$queryRaw`SELECT * FROM Table ORDER BY ${ordering};`
  • Prisma 将 $queryRaw$queryRawUnsafe 返回的任何数据库值映射到它们相应的 JavaScript 类型。 了解更多.

  • $queryRaw 不支持 PostgreSQL 数据库中的动态表名。 了解更多

返回类型

$queryRaw 返回一个数组。每个对象对应于一个数据库记录

[
{ id: 1, email: '[email protected]', name: 'Emelie' },
{ id: 2, email: '[email protected]', name: 'Yin' },
]

您也可以 $queryRaw 的结果设置类型.

签名

$queryRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): PrismaPromise<T>;

$queryRaw 结果设置类型

PrismaPromise<T> 使用 泛型类型参数 T。当您调用 $queryRaw 方法时,您可以确定 T 的类型。在以下示例中,$queryRaw 返回 User[]

// import the generated `User` type from the `@prisma/client` module
import { User } from '@prisma/client'

const result = await prisma.$queryRaw<User[]>`SELECT * FROM User`
// result is of type: `User[]`

注意:如果您没有提供类型,$queryRaw 默认设置为 unknown

如果您要选择模型的 特定字段 或想要包含关系,请参考有关 利用 Prisma 客户端的生成类型 的文档,如果您想确保结果被正确地设置类型。

使用原始 SQL 时的类型注意事项

当您为 $queryRaw 的结果设置类型时,原始数据可能并不总是与建议的 TypeScript 类型匹配。例如,以下 Prisma 模型包含一个名为 publishedBoolean 字段

model Post {
id Int @id @default(autoincrement())
published Boolean @default(false)
title String
content String?
}

以下查询返回所有帖子。然后,它打印出每个 Postpublished 字段的值

const result = await prisma.$queryRaw<Post[]>`SELECT * FROM Post`

result.forEach((x) => {
console.log(x.published)
})

对于常规的 CRUD 查询,Prisma 客户端查询引擎会为所有数据库标准化返回类型。使用原始查询不会。如果数据库提供程序是 MySQL,则返回的值为 10。但是,如果数据库提供程序是 PostgreSQL,则值为 truefalse

注意:Prisma 将 JavaScript 整数发送到 PostgreSQL 作为 INT8。这可能会与您的用户定义函数发生冲突,这些函数只接受 INT4 作为输入。如果您将 $queryRaw 与 PostgreSQL 数据库一起使用,请将输入类型更新为 INT8,或将查询参数强制转换为 INT4

PostgreSQL 中的动态表名

无法内插表名。这意味着您不能将动态表名与 $queryRaw 一起使用。相反,您必须使用 $queryRawUnsafe,如下所示

let userTable = 'User'
let result = await prisma.$queryRawUnsafe(`SELECT * FROM ${userTable}`)

请注意,如果您将 $queryRawUnsafe 与用户输入一起使用,则存在 SQL 注入攻击的风险。 了解更多.

$queryRawUnsafe()

$queryRawUnsafe() 方法允许您将原始字符串(或模板字符串)传递到数据库。

警告

如果您将此方法与用户输入一起使用(换句话说,SELECT * FROM table WHERE columnx = ${userInput}),那么您就会面临 SQL 注入攻击的可能性。SQL 注入攻击可能会使您的数据暴露于修改或删除。

只要可能,您应该使用 $queryRaw 方法。如果使用得当,$queryRaw 方法要安全得多,但请注意,$queryRaw 方法在某些情况下也可能变得脆弱。有关更多信息,请参阅下面的 SQL 注入预防 部分。

以下查询返回 User 表中每个记录的所有字段

// import the generated `User` type from the `@prisma/client` module
import { User } from '@prisma/client'

const result = await prisma.$queryRawUnsafe('SELECT * FROM User')

您也可以运行参数化查询。以下示例返回所有电子邮件包含字符串 [email protected] 的用户

prisma.$queryRawUnsafe(
'SELECT * FROM users WHERE email = $1',
'[email protected]'
)

注意:Prisma 将 JavaScript 整数发送到 PostgreSQL 作为 INT8。这可能会与您仅接受 INT4 作为输入的用户定义函数冲突。如果您将参数化的 $queryRawUnsafe 查询与 PostgreSQL 数据库结合使用,请将输入类型更新为 INT8,或将查询参数转换为 INT4

有关使用参数化查询的更多详细信息,请参阅下面的 参数化查询 部分。

签名

$queryRawUnsafe<T = unknown>(query: string, ...values: any[]): PrismaPromise<T>;

$executeRaw

$executeRaw 返回受数据库操作影响的行数,例如 UPDATEDELETE。此函数不会返回数据库记录。以下查询更新数据库中的记录并返回已更新的记录数

const result: number =
await prisma.$executeRaw`UPDATE User SET active = true WHERE emailValidated = true`

该方法实现为 带标签的模板,允许您传递一个模板字面量,您可以在其中轻松插入您的 变量。反过来,Prisma 客户端会创建针对 SQL 注入安全的准备好的语句

const emailValidated = true
const active = true

const result: number =
await prisma.$executeRaw`UPDATE User SET active = ${active} WHERE emailValidated = ${emailValidated};`
警告

如果您使用字符串构建将不受信任的输入合并到传递给此方法的查询中,那么您就会面临 SQL 注入攻击的可能性。SQL 注入攻击可能会使您的数据暴露于修改或删除。首选机制是在运行此方法时包含查询文本。有关此风险以及如何防止它的示例,请参阅下面的 SQL 注入预防 部分。

注意事项

请注意

  • $executeRaw 不支持在单个字符串中使用多个查询(例如,ALTER TABLECREATE TABLE 同时使用)。

  • Prisma Client 提交准备好的语句,准备好的语句只允许使用一部分 SQL 语句。例如,START TRANSACTION 不允许。您可以了解更多有关 MySQL 在准备好的语句中允许的语法

  • PREPARE 不支持 ALTER - 请参阅 解决方法

  • 模板变量不能在 SQL 字符串字面量内使用。例如,以下查询 将无法 正常工作

    const name = 'Bob'
    await prisma.$executeRaw`UPDATE user SET greeting = 'My name is ${name}';`

    相反,您可以将整个字符串作为变量传递,或者使用字符串连接

    const name = 'My name is Bob'
    await prisma.$executeRaw`UPDATE user SET greeting = ${name};`
    const name = 'Bob'
    await prisma.$executeRaw`UPDATE user SET greeting = 'My name is ' || ${name};`
  • 模板变量只能用于数据值(如上面的示例中的 email)。变量不能用于标识符,例如列名、表名或数据库名,也不能用于 SQL 关键字。例如,以下两个查询 将无法 正常工作

    const myTable = 'user'
    await prisma.$executeRaw`UPDATE ${myTable} SET active = true;`
    const ordering = 'desc'
    await prisma.$executeRaw`UPDATE User SET active = true ORDER BY ${desc};`

返回值类型

$executeRaw 返回一个 number

签名

$executeRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): PrismaPromise<number>;

$executeRawUnsafe()

$executeRawUnsafe() 方法允许您将原始字符串(或模板字符串)传递到数据库。与 $executeRaw 一样,它不会返回数据库记录,而是返回受影响的行数。

警告

如果您将此方法与用户输入一起使用(换句话说,SELECT * FROM table WHERE columnx = ${userInput}),那么您就会面临 SQL 注入攻击的可能性。SQL 注入攻击可能会使您的数据暴露于修改或删除。

只要有可能,您应该使用 $executeRaw 方法。正确使用时,$executeRaw 方法更安全,但请注意,$executeRaw 方法在某些情况下也可能变得容易受到攻击。有关更多信息,请参阅下面的 SQL 注入防御 部分。

以下示例使用模板字符串来更新数据库中的记录。然后它返回已更新的记录数

const emailValidated = true
const active = true

const result = await prisma.$executeRawUnsafe(
`UPDATE User SET active = ${active} WHERE emailValidated = ${emailValidated}`
)

同样也可以写成参数化的查询

const result = prisma.$executeRawUnsafe(
'UPDATE User SET active = $1 WHERE emailValidated = $2',
'[email protected]',
true
)

有关使用参数化查询的更多详细信息,请参阅下面的 参数化查询 部分。

签名

$executeRawUnsafe<T = unknown>(query: string, ...values: any[]): PrismaPromise<number>;

原始查询类型映射

Prisma 将 $queryRaw$queryRawUnsafe 返回的任何数据库值映射到其对应的 JavaScript 类型。此行为与 findMany() 等常规 Prisma 查询方法相同。

info

功能可用性

  • 在 v3.14.x 和 v3.15.x 中,原始查询类型映射可通过预览功能 improvedQueryRaw 使用。我们在 4.0.0 版本中使原始查询类型映射 全面可用,因此您不需要在 4.0.0 或更高版本中使用 improvedQueryRaw
  • 在 4.0.0 版本之前,SQLite 不支持原始查询类型映射。

例如,使用一个原始查询,从表中选择带有 BigIntBytesDecimalDate 类型的列

const result =
await prisma.$queryRaw`SELECT bigint, bytes, decimal, date FROM "Table";`

console.log(result)
显示CLI结果
{ bigint: BigInt("123"), bytes: Buffer.from([1, 2]), decimal: Decimal("12.34"), date: Date("<some_date>") }

result 对象中,数据库值已映射到相应的 JavaScript 类型。

下表显示了数据库中使用的类型与原始查询返回的 JavaScript 类型之间的转换

数据库类型JavaScript 类型
TextString
32 位整数Number
浮点数Number
双精度数Number
64 位整数BigInt
Decimal / numericDecimal
BytesBuffer
JsonObject
DateTimeDate
DateDate
TimeDate
UuidString
XmlString

请注意,每个数据库类型的准确名称在不同的数据库之间会有所不同 - 例如,布尔类型在 PostgreSQL 中被称为 boolean,而在 CockroachDB 中被称为 STRING。有关每个数据库类型名称的完整详细信息,请参阅 标量类型参考

原始查询类型转换行为

使用 Prisma Client 的原始查询可能需要将参数设置为 SQL 函数或查询的预期类型。Prisma Client 不会进行隐式类型转换。

例如,使用 PostgreSQL 的 LENGTH 函数的以下查询,它只接受 text 类型作为输入

await prisma.$queryRaw`SELECT LENGTH(${42});`

此查询返回错误

// ERROR: function length(integer) does not exist
// HINT: No function matches the given name and argument types. You might need to add explicit type casts.

在这种情况下,解决方案是将 42 显式转换为 text 类型

await prisma.$queryRaw`SELECT LENGTH(${42}::text);`
info

功能可用性:此功能从 4.0.0 版本开始 全面可用。在 v3.14.x 和 v3.15.x 中,它可以通过预览功能 improvedQueryRaw 使用。

在 4.0.0 版本之前,Prisma ORM 会将 42 静默地转换为 text,并且不需要显式转换。

另一方面,以下原始查询现在可以正常工作,返回一个整数结果,并且在之前会失败

await prisma.$queryRaw`SELECT ${1.5}::int as int`

// Now: [{ int: 2 }]
// Before: db error: ERROR: incorrect binary data format in bind parameter 1

事务

在 2.10.0 及更高版本中,您可以在 事务 中使用 .$executeRaw().$queryRaw()

使用变量

$executeRaw$queryRaw 被实现为 带标签的模板。带标签的模板是使用 Prisma Client 中原始 SQL 的变量的推荐方法。

以下示例包含一个名为 ${userId} 的占位符

const userId = 42
const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${userId};`

✔ 使用带标签的模板版本的 $queryRaw$executeRaw 的优点包括

  • Prisma Client 会转义所有变量。
  • 带标签的模板与数据库无关 - 您不需要记住变量是否应该写为 $1(PostgreSQL)或 ?(MySQL)。
  • SQL 模板标签 让您可以访问 有用的帮助程序
  • 嵌入式命名变量更易于阅读。

注意:您不能将表名或列名传递到带标签的模板占位符中。例如,您不能基于某个条件进行 SELECT ? 并传递 *id, name

带标签的模板帮助程序

Prisma Client 特别使用了 SQL 模板标签,它公开了一些帮助程序。例如,以下查询使用 join() 传递一个 ID 列表

import { Prisma } from '@prisma/client'

const ids = [1, 3, 5, 10, 20]
const result =
await prisma.$queryRaw`SELECT * FROM User WHERE id IN (${Prisma.join(ids)})`

以下示例使用 emptysql 帮助程序来根据 userName 是否为空来更改查询

import { Prisma } from '@prisma/client'

const userName = ''
const result = await prisma.$queryRaw`SELECT * FROM User ${
userName ? Prisma.sql`WHERE name = ${userName}` : Prisma.empty // Cannot use "" or NULL here!
}`

ALTER 限制(PostgreSQL)

PostgreSQL 不支持在准备好的语句中使用 ALTER,这意味着以下查询将无法正常工作

await prisma.$executeRaw`ALTER USER prisma WITH PASSWORD "${password}"`
await prisma.$executeRaw(
Prisma.sql`ALTER USER prisma WITH PASSWORD "${password}"`
)

您可以使用以下查询,但请注意,这可能是不安全的,因为 ${password} 未转义

await prisma.$executeRawUnsafe('ALTER USER prisma WITH PASSWORD "$1"', password})

不支持的类型

Unsupported 类型$queryRaw$queryRawUnsafe 中使用之前,需要转换为 Prisma Client 支持的类型。例如,使用以下模型,它有一个 location 字段,该字段的类型为 Unsupported

model Country {
location Unsupported("point")?
}

以下对不支持字段的查询将无法正常工作

await prisma.$queryRaw`SELECT location FROM Country;`

相反,将 Unsupported 字段转换为任何支持的 Prisma Client 类型,如果您的 Unsupported 列支持转换

您可能希望将 Unsupported 列转换为的最常见的类型是 String。例如,在 PostgreSQL 上,这将映射到 text 类型

await prisma.$queryRaw`SELECT location::text FROM Country;`

因此,数据库将提供数据的 String 表示,而 Prisma Client 支持此表示。

有关支持的 Prisma 类型的详细信息,请参阅相关数据库的 Prisma 连接器概述

SQL 注入防御

在 Prisma Client 中避免 SQL 注入的理想方法是在可能的情况下使用 ORM 模型来执行查询。

如果无法使用 ORM 模型,并且需要使用原始查询,Prisma Client 提供了多种原始方法,但务必安全地使用这些方法。

本节将提供使用这些方法的安全和不安全示例。您可以在 Prisma Playground 中测试这些示例。

$queryRaw$executeRaw

$queryRaw$executeRaw 的简单安全使用

当您使用带标签的模板并以预处理语句的形式发送所有查询时,这些方法可以降低 SQL 注入的风险。

$queryRaw`...` // Tagged template
$executeRaw`...` // Tagged template

以下示例对 SQL 注入是安全的 ✅

const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`
const result =
await prisma.$queryRaw`SELECT id, name FROM "User" WHERE name = ${inputString}`

console.log(result)

$queryRaw$executeRaw 的不安全使用

但是,也可以以不安全的方式使用这些方法。

一种方法是通过人工生成一个不安全地连接用户输入的带标签的模板。

以下示例容易受到 SQL 注入攻击 ❌

// Unsafely generate query text
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"` // SQL Injection
const query = `SELECT id, name FROM "User" WHERE name = ${inputString}`

// Version for Typescript
const stringsArray: any = [...[query]]

// Version for Javascript
const stringsArray = [...[query]]

// Use the `raw` property to impersonate a tagged template
stringsArray.raw = [query]

// Use queryRaw
const result = await prisma.$queryRaw(stringsArray)
console.log(result)

另一种使这些方法容易受到攻击的方式是错误使用 Prisma.raw 函数。

以下示例都容易受到 SQL 注入攻击 ❌

const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`
const result =
await prisma.$queryRaw`SELECT id, name FROM "User" WHERE name = ${Prisma.raw(
inputString
)}`
console.log(result)
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`
const result = await prisma.$queryRaw(
Prisma.raw(`SELECT id, name FROM "User" WHERE name = ${inputString}`)
)
console.log(result)
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`
const query = Prisma.raw(
`SELECT id, name FROM "User" WHERE name = ${inputString}`
)
const result = await prisma.$queryRaw(query)
console.log(result)

在更复杂的场景中安全使用 $queryRaw$executeRaw

将原始查询与查询执行分开构建

如果您想在其他地方或与参数分开构建原始查询,则需要使用以下方法之一。

在此示例中,sql 辅助方法用于通过安全地包含变量来构建查询文本。它对 SQL 注入是安全的 ✅

// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`

// Safe if the text query below is completely trusted content
const query = Prisma.sql`SELECT id, name FROM "User" WHERE name = ${inputString}`

const result = await prisma.$queryRaw(query)
console.log(result)

在此示例中,对 SQL 注入是安全的 ✅,sql 辅助方法用于构建查询文本,包括用于输入值的占位符。每个变量都由一个标记符号表示(MySQL 为 ?,PostgreSQL 为 $1$2 等)。请注意,这些示例仅显示 PostgreSQL 查询。

// Version for Typescript
const query: any

// Version for Javascript
const query

// Safe if the text query below is completely trusted content
query = Prisma.sql`SELECT id, name FROM "User" WHERE name = $1`

// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`
query.values = [inputString]

const result = await prisma.$queryRaw(query)
console.log(result)

注意:PostgreSQL 变量由 $1 等表示。

在其他地方或分阶段构建原始查询

如果您想在执行查询的地方之外构建原始查询,理想的方法是从查询的段创建 Sql 对象并传递参数值。

在以下示例中,我们有两个要参数化的变量。只要传递给 Prisma.sql 的查询字符串仅包含受信任的内容,此示例对 SQL 注入是安全的 ✅

// Example is safe if the text query below is completely trusted content
const query1 = `SELECT id, name FROM "User" WHERE name = ` // The first parameter would be inserted after this string
const query2 = ` OR name = ` // The second parameter would be inserted after this string

const inputString1 = "Fred"
const inputString2 = `'Sarah' UNION SELECT id, title FROM "Post"`

const query = Prisma.sql([query1, query2, ""], inputString1, inputString2)
const result = await prisma.$queryRaw(query);
console.log(result);

注意:请注意,作为第一个参数传递给 Prisma.sql 的字符串数组需要在末尾有一个空字符串,因为 sql 函数期望的查询段数比参数数量多一个。

如果您想将原始查询构建成一个大字符串,这仍然是可能的,但需要谨慎,因为它使用的是潜在的危险的 Prisma.raw 方法。您还需要使用数据库的正确参数标记构建查询,因为 Prisma 通常无法为相关数据库提供标记。

只要传递给 Prisma.raw 的查询字符串仅包含受信任的内容,以下示例对 SQL 注入是安全的 ✅

// Version for Typescript
const query: any

// Version for Javascript
const query

// Example is safe if the text query below is completely trusted content
const query1 = `SELECT id, name FROM "User" `
const query2 = `WHERE name = $1 `

query = Prisma.raw(`${query1}${query2}`)

// inputString can be untrusted input
const inputString = `'Sarah' UNION SELECT id, title FROM "Post"`
query.values = [inputString]

const result = await prisma.$queryRaw(query)
console.log(result)

$queryRawUnsafe$executeRawUnsafe

不安全地使用 $queryRawUnsafe$executeRawUnsafe

如果您无法使用带标签的模板,您可以改用 $queryRawUnsafe$executeRawUnsafe。但是,请注意,这些函数会大大增加代码中出现 SQL 注入漏洞的风险

以下示例连接了 queryinputString。在此示例中,Prisma Client ❌ 无法转义 inputString,这使其容易受到 SQL 注入攻击。

const inputString = '"Sarah" UNION SELECT id, title, content FROM Post' // SQL Injection
const query = 'SELECT id, name, email FROM User WHERE name = ' + inputString
const result = await prisma.$queryRawUnsafe(query)

console.log(result)

参数化查询

作为带标签的模板的替代方案,$queryRawUnsafe 支持标准参数化查询,其中每个变量都由一个符号表示(MySQL 为 ?,PostgreSQL 为 $1$2 等)。请注意,这些示例仅显示 PostgreSQL 查询。

以下示例对 SQL 注入是安全的 ✅

const userName = 'Sarah'
const email = '[email protected]'
const result = await prisma.$queryRawUnsafe(
'SELECT * FROM User WHERE (name = $1 OR email = $2)',
userName,
email
)

注意:PostgreSQL 变量由 $1$2 表示。

与带标签的模板一样,Prisma Client 在以这种方式提供变量时会转义所有变量。

注意:您不能将表名或列名作为变量传递到参数化查询中。例如,您不能根据某些条件传递 SELECT ? 并传入 *id, name

参数化的 PostgreSQL ILIKE 查询

当您使用 ILIKE 时,% 通配符应该包含在变量本身中,而不是查询 (string) 中。此示例对 SQL 注入是安全的 ✅。

const userName = 'Sarah'
const emailFragment = 'prisma.io'
const result = await prisma.$queryRawUnsafe(
'SELECT * FROM "User" WHERE (name = $1 OR email ILIKE $2)',
userName,
`%${emailFragment}`
)

注意:使用 %$2 作为参数将不起作用。

使用 MongoDB 的原始查询

对于 3.9.0 及更高版本的 MongoDB,Prisma Client 公开了三种方法,允许您发送原始查询。您可以使用

  • $runCommandRaw 对数据库运行命令
  • <model>.findRaw 查找与过滤器匹配的一个或多个文档。
  • <model>.aggregateRaw 对集合执行聚合操作。

$runCommandRaw()

$runCommandRaw() 对数据库运行原始 MongoDB 命令。作为输入,它接受所有 MongoDB 数据库命令,但以下情况除外

当您使用 $runCommandRaw() 运行 MongoDB 数据库命令时,请注意以下事项

  • 调用 $runCommandRaw() 时传递的对象必须遵循 MongoDB 数据库命令的语法。
  • 您必须使用适合 MongoDB 数据库命令的角色连接到数据库。

在以下示例中,查询插入了两个具有相同 _id 的记录。这绕过了正常的文档验证。

prisma.$runCommandRaw({
insert: 'Pets',
bypassDocumentValidation: true,
documents: [
{
_id: 1,
name: 'Felinecitas',
type: 'Cat',
breed: 'Russian Blue',
age: 12,
},
{
_id: 1,
name: 'Nao Nao',
type: 'Dog',
breed: 'Chow Chow',
age: 2,
},
],
})
警告

不要对包含 "find""aggregate" 命令的查询使用 $runCommandRaw(),因为您可能无法获取所有数据。这是因为 MongoDB 返回一个 游标,该游标附加到您的 MongoDB 会话,并且您可能无法每次都访问同一个 MongoDB 会话。对于这些查询,您应该改用专门的 findRaw()aggregateRaw() 方法。

返回类型

$runCommandRaw() 返回一个 JSON 对象,其形状取决于输入。

签名

$runCommandRaw(command: InputJsonObject): PrismaPromise<JsonObject>;

findRaw()

<model>.findRaw() 返回实际的数据库记录。它将在 User 集合中找到与过滤器匹配的一个或多个文档

const result = await prisma.user.findRaw({
filter: { age: { $gt: 25 } },
options: { projection: { _id: false } },
})

返回类型

<model>.findRaw() 返回一个 JSON 对象,其形状取决于输入。

签名

<model>.findRaw(args?: {filter?: InputJsonObject, options?: InputJsonObject}): PrismaPromise<JsonObject>;
  • filter:查询谓词过滤器。如果未指定,则集合中的所有文档都将匹配 谓词
  • options:传递给 find 命令 的其他选项。

aggregateRaw()

<model>.aggregateRaw() 返回聚合的数据库记录。它将在 User 集合中执行聚合操作

const result = await prisma.user.aggregateRaw({
pipeline: [
{ $match: { status: 'registered' } },
{ $group: { _id: '$country', total: { $sum: 1 } } },
],
})

返回类型

<model>.aggregateRaw() 返回一个 JSON 对象,其形状取决于输入。

签名

<model>.aggregateRaw(args?: {pipeline?: InputJsonObject[], options?: InputJsonObject}): PrismaPromise<JsonObject>;
  • pipeline:一个聚合阶段数组,通过 聚合管道 处理和转换文档流。
  • options: 传递给 aggregate 命令 的附加选项。