REST API:联表加载(Population)与字段选择
页面摘要: 使用
populate参数在 REST API 响应中纳入关联、媒体字段、组件与动态区域。使用fields参数仅返回特定字段。
REST API 默认不会联表加载(populate)任何关联、媒体字段、组件或动态区域。使用 populate 参数 来联表加载特定字段。使用 fields 参数 在查询结果中仅返回特定字段。
字段选择(Field selection)
查询可以接受一个 fields 参数,以仅选择部分字段。默认情况下,REST API 仅返回以下类型的字段:
- 字符串类型:
string、text、richtext、enumeration、email、password和uid, - 日期类型:
date、time、datetime和timestamp, - 数字类型:
integer、biginteger、float和decimal, - 通用类型:
boolean、array和JSON。
| 用例 | 参数语法示例 |
|---|---|
| 选择单个字段 | fields=name |
| 选择多个字段 | fields[0]=name&fields[1]=description |
字段选择对关联、媒体、组件或动态区域字段无效。要联表加载这些字段,请使用 populate 参数。
使用 fields 参数在响应中仅选择特定字段。
cURL
curl 'http://localhost:1337/api/restaurants?fields[0]=name&fields[1]=description' \
-H 'Authorization: Bearer <token>'
JavaScript
const qs = require('qs');
const query = qs.stringify(
{
fields: ['name', 'description'],
},
{
encodeValuesOnly: true, // 美化 URL
}
);
await request(`/api/restaurants?${query}`);
响应
{
"data": [
{
"id": 4,
"Name": "Pizzeria Arrivederci",
"Description": [
{
"type": "paragraph",
"children": [
{
"type": "text",
"text": "Specialized in pizza, we invite you to rediscover our classics, such as 4 Formaggi or Calzone, and our original creations such as Do Luigi or Nduja."
}
]
}
],
"documentId": "lr5wju2og49bf820kj9kz8c3"
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}
联表加载(Population)
REST API 默认不会联表加载任何类型的字段,因此除非传入 populate 参数以联表加载各类字段,否则不会联表加载关联、媒体字段、组件或动态区域。被联表加载的关联始终返回完整对象;REST API 目前无法仅返回 ID 数组。
必须为被联表加载的 content-types 启用 find 权限。如果某个角色无权访问某个 content-type,则该 content-type 不会被联表加载(有关如何为 content-types 启用 find 权限的更多信息,请参阅 用户与权限(Users & Permissions))。
你可以单独使用 populate 参数,也可以 与其它多个运算符组合,以更精细地控制联表加载。
populate=deep 插件在 Strapi 中不被推荐使用。
查询字符串中过长的 populate 列表(大量 populate[0]、populate[1]……条目)会受到查询解析器 arrayLimit(默认值:100)的限制。要允许更长的列表,请提高 strapi::query 中间件 上的 arrayLimit。值越大,每次请求的解析开销越高。
下表列出了联表加载的用例及示例语法。每一行都链接到「理解联表加载」指南以查看详情:
| 用例 | 参数语法示例 | 可阅读详细说明 |
|---|---|---|
| 联表加载全部内容,深度 1 层,包含媒体字段、关联、组件与动态区域 | populate=* | 联表加载全部关联与字段,深度 1 层 |
| 联表加载单个关联,深度 1 层 | populate=a-relation-name | 针对特定关联联表加载 1 层深度 |
| 联表加载多个关联,深度 1 层 | populate[0]=relation-name&populate[1]=another-relation-name&populate[2]=yet-another-relation-name | 针对特定关联联表加载 1 层深度 |
| 联表加载部分关联,多层深度 | populate[root-relation-name][populate][0]=nested-relation-name | 针对特定关联联表加载多层深度 |
| 联表加载组件 | populate[0]=component-name | 联表加载组件 |
| 联表加载组件及其某个嵌套组件 | populate[0]=component-name&populate[1]=component-name.nested-component-name | 联表加载组件 |
| 联表加载动态区域(仅其第一层标量字段) | populate[0]=dynamic-zone-name | 联表加载动态区域 |
| 联表加载动态区域,包含组件专属字段、嵌套组件与关联 | populate[dynamic-zone-name][on][component-category.component-name][populate][relation-name][populate][0]=field-name | 联表加载动态区域 |
要构建包含多层联表加载的复杂查询,请使用 交互式查询构建器 工具。更多详细说明与示例,请参阅 REST API 指南。
将联表加载与其它运算符组合
你可以在联表加载查询中将 populate 运算符与字段选择、过滤器和排序等其它运算符组合使用。
顶层分页参数(例如 pagination[page] 与 pagination[pageSize])可与 populate 配合,对主查询结果进行分页。但是,你无法将分页参数直接应用于被联表加载的关联,以限制每个结果中返回的相关条目数量(REST API 不支持对关联进行嵌套分页)。
配合字段选择进行联表加载
fields 与 populate 可以组合使用。
组合 fields 与 populate 参数,在主条目及其关联上选择特定字段。
cURL
curl 'http://localhost:1337/api/articles?fields[0]=title&fields[1]=slug&populate[headerImage][fields][0]=name&populate[headerImage][fields][1]=url' \
-H 'Authorization: Bearer <token>'
JavaScript
const qs = require('qs');
const query = qs.stringify(
{
fields: ['title', 'slug'],
populate: {
headerImage: {
fields: ['name', 'url'],
},
},
},
{
encodeValuesOnly: true, // 美化 URL
}
);
await request(`/api/articles?${query}`);
响应
{
"data": [
{
"id": 1,
"documentId": "h90lgohlzfpjf3bvan72mzll",
"title": "Test Article",
"slug": "test-article",
"headerImage": {
"id": 1,
"documentId": "cf07g1dbusqr8mzmlbqvlegx",
"name": "17520.jpg",
"url": "/uploads/17520_73c601c014.jpg"
}
}
],
"meta": {}
}
配合过滤进行联表加载
filters 与 populate 可以组合使用。
组合 populate 与排序、过滤参数,以精炼返回的相关条目。
cURL
curl 'http://localhost:1337/api/articles?populate[categories][sort][0]=name%3Aasc&populate[categories][filters][name][$eq]=Cars' \
-H 'Authorization: Bearer <token>'
JavaScript
const qs = require('qs');
const query = qs.stringify(
{
populate: {
categories: {
sort: ['name:asc'],
filters: {
name: {
$eq: 'Cars',
},
},
},
},
},
{
encodeValuesOnly: true, // 美化 URL
}
);
await request(`/api/articles?${query}`);
响应
{
"data": [
{
"id": 1,
"documentId": "a1b2c3d4e5d6f7g8h9i0jkl",
"title": "Test Article",
"categories": {
"data": [
{
"id": 2,
"documentId": "jKd8djla9ndalk98hflj3",
"name": "Cars"
}
]
}
}
],
"meta": {}
}
对于多对多(many-to-many)及其他连接表关联,在 populate 对象中显式指定 sort 会覆盖默认的连接顺序。省略 sort 可保留连接顺序(即条目被关联的顺序)。
在生产环境中,请始终使用显式联表加载,而非 populate=* 之类的通配符。将联表加载深度限制在 2-3 层,并考虑将联表加载逻辑集中到路由中间件中。请参阅 Strapi 博客上的 构建高性能 Strapi 应用。
被联表加载时,空的 morphMany 关联(包括诸如画廊这类 type: 'media', multiple: true 的字段)会返回 [] 而非 null,与 oneToMany 和 manyToMany 保持一致。有关迁移指引,请参阅 morphMany 序列化破坏性变更。