REST API:联表加载(Population)与字段选择

页面摘要: 使用 populate 参数在 REST API 响应中纳入关联、媒体字段、组件与动态区域。使用 fields 参数仅返回特定字段。

REST API 默认不会联表加载(populate)任何关联、媒体字段、组件或动态区域。使用 populate 参数 来联表加载特定字段。使用 fields 参数 在查询结果中仅返回特定字段。

TIP

Strapi 利用 qs 库 解析嵌套对象的能力来创建更复杂的查询。

使用 qs 直接生成复杂查询,而不是手动创建。本文档中的示例展示了如何使用 qs。

如果你更喜欢使用在线工具而不是在本地用 qs 生成查询,也可以使用交互式查询构建器。

字段选择(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
NOTE

字段选择对关联、媒体、组件或动态区域字段无效。要联表加载这些字段,请使用 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 数组。

WARNING

必须为被联表加载的 content-types 启用 find 权限。如果某个角色无权访问某个 content-type,则该 content-type 不会被联表加载(有关如何为 content-types 启用 find 权限的更多信息,请参阅 用户与权限(Users & Permissions))。

你可以单独使用 populate 参数,也可以 与其它多个运算符组合,以更精细地控制联表加载。

WARNING

populate=deep 插件在 Strapi 中不被推荐使用。

NOTE

查询字符串中过长的 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联表加载动态区域
TIP

要构建包含多层联表加载的复杂查询,请使用 交互式查询构建器 工具。更多详细说明与示例,请参阅 REST API 指南。

将联表加载与其它运算符组合

你可以在联表加载查询中将 populate 运算符与字段选择、过滤器和排序等其它运算符组合使用。

NOTE

顶层分页参数(例如 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": {}
}
NOTE

对于多对多(many-to-many)及其他连接表关联,在 populate 对象中显式指定 sort 会覆盖默认的连接顺序。省略 sort 可保留连接顺序(即条目被关联的顺序)。

性能提示

在生产环境中,请始终使用显式联表加载,而非 populate=* 之类的通配符。将联表加载深度限制在 2-3 层,并考虑将联表加载逻辑集中到路由中间件中。请参阅 Strapi 博客上的 构建高性能 Strapi 应用。

NOTE

被联表加载时,空的 morphMany 关联(包括诸如画廊这类 type: 'media', multiple: true 的字段)会返回 [] 而非 null,与 oneToMany 和 manyToMany 保持一致。有关迁移指引,请参阅 morphMany 序列化破坏性变更。