Select
默认情况下,Payload 的 API 会返回给定 collection 或 global 的 所有字段。但你可能并不需要所有这些数据。有时,你可能只需要响应中的几个字段,这可以加快 Payload API 的速度,并减少从 API 发送给你的 JSON 数据量。
这就是 Payload 的 select
功能的用武之地。通过它,你可以精确指定要从 API 中检索哪些字段。
本地 API
要在本地 API中指定 select
,你可以在查询中使用 select
选项:
import type { Payload } from 'payload'
// 包含模式
const getPosts = async (payload: Payload) => {
const posts = await payload.find({
collection: 'posts',
select: {
text: true,
// 从 group 中选择特定字段
group: {
number: true,
},
// 选择 array 的所有字段
array: true,
}, // highlight-line
})
return posts
}
// 排除模式
const getPosts = async (payload: Payload) => {
const posts = await payload.find({
collection: 'posts',
// 选择除 array 和 group.number 之外的所有内容
select: {
array: false,
group: {
number: false,
},
}, // highlight-line
})
return posts
}
重要提示: 为了高效执行带有 select
的查询,Payload
会在数据库级别实现你的 select
查询。因此,你的
beforeRead
和 afterRead
钩子可能不会接收到完整的 doc
。为确保某些字段始终被选中(无论 select
查询如何),以便你的钩子/访问控制可以使用,你可以使用 collection 配置中的 forceSelect
属性。
REST API
要在 REST API 中指定 select 查询,你可以在请求中使用 select
参数:
fetch(
'https://localhost:3000/api/posts?select[color]=true&select[group][number]=true',
) // highlight-line
.then((res) => res.json())
.then((data) => console.log(data))
要理解这种语法,需要明白复杂的 URL 查询字符串会被解析为 JSON 对象。这个例子还不算太复杂,但更复杂的查询会不可避免地变得更难编写。
因此,我们推荐使用非常实用且广泛使用的 qs-esm
包,将你的 JSON/对象格式的查询转换为查询字符串:
import { stringify } from 'qs-esm'
import type { Where } from 'payload'
const select: Where = {
text: true,
group: {
number: true,
},
// 这个查询可以复杂得多
// QS 都能完美处理
}
const getPosts = async () => {
const stringifiedQuery = stringify(
{
select, // 确保 `qs` 也添加 `select` 属性!
},
{ addQueryPrefix: true },
)
const response = await fetch(
`http://localhost:3000/api/posts${stringifiedQuery}`,
)
// 继续处理响应...
}
提醒: 使用 /api/globals
端点的 Globals 也同样适用。
defaultPopulate 集合配置属性
defaultPopulate
属性允许你指定从另一个文档填充集合时要选择的字段。这对于只需要 slug
而非整个文档的链接特别有用。
通过此功能,你可以显著减少从 Relationship 或 Upload 字段填充的 JSON 数据量。
例如,在你的内容模型中,可能有一个 Link
字段链接到其他页面。当你获取这些链接时,实际上只需要页面的 slug
。
加载所有页面内容、相关链接和其他所有内容会显得过度,并且会拖慢你的 Payload API。相反,你可以在 Pages
集合上定义 defaultPopulate
属性,这样当 Payload "填充" 相关页面时,它只会选择 slug
字段,从而返回显著减少的 JSON 数据:
import type { CollectionConfig } from 'payload'
// 可以传递 TSlug 泛型来为 `defaultPopulate` 提供类型安全。
// 如果省略,`defaultPopulate` 类型将解析为 `SelectType`。
export const Pages: CollectionConfig<'pages'> = {
slug: 'pages',
// 指定 `select`。
defaultPopulate: {
slug: true,
},
fields: [
{
name: 'slug',
type: 'text',
required: true,
},
],
}
重要提示: 当在启用了 Uploads 的集合上使用 defaultPopulate
,
并且你想选择 url
字段时,必须同时指定 filename: true
,
否则 Payload 将无法构建正确的文件 URL,而是返回 url: null
。
populate
设置 defaultPopulate
将强制 Payload 在每次执行关联文档的 "population" 操作时,只查询并返回指定的字段。不过,你可以通过 Local API 和 REST API 中的 populate
属性来覆盖 defaultPopulate
:
Local API:
import type { Payload } from 'payload'
const getPosts = async (payload: Payload) => {
const posts = await payload.find({
collection: 'posts',
populate: {
// 从 "pages" collection 的关联文档中仅选择 `text` 字段
// 无论 "pages" collection 的 `defaultPopulate` 设置为何值,
// 都会被此处的设置覆盖,最终只返回 `text` 字段
pages: {
text: true,
}, // highlight-line
},
})
return posts
}
REST API:
fetch('https://localhost:3000/api/posts?populate[pages][text]=true') // highlight-line
.then((res) => res.json())
.then((data) => console.log(data))