Skip to main content

🧠 理解 REST API 的 populate 参数

🌐 🧠 Understanding the populate parameter for the REST API

🏗 Work in progress

此页面的内容可能尚未与 Strapi 5 完全同步。

🌐 The content of this page might not be fully up-to-date with Strapi 5 yet.

Note: Example responses might differ from your experience

此页面的内容可能尚未与 Strapi 5 完全同步:

🌐 The content of this page might not be fully up-to-date with Strapi 5 yet:

  • 所有概念信息和解释都是正确且最新的。
  • 但是,在示例中,响应内容可能略有不同。

示例将在 Strapi 5.0.0(稳定版本)发布之后以及 FoodAdvisor 示例应用升级到 Strapi 5 后完全更新。

但是,响应示例略有不同不应妨碍你掌握本页所教授的基本概念。

🌐 However, having slightly different response examples should not prevent you from grasping the essential concepts taught in this page.

在使用 Strapi 的 REST API 查询内容类型时,默认情况下,响应只包含顶层字段,不包含任何关联、媒体字段、组件或动态区域。

🌐 When querying content-types with Strapi's REST API, by default, responses only include top-level fields and do not include any relations, media fields, components, or dynamic zones.

在 Strapi REST API 的上下文中,Populating 意味着通过返回比默认返回的字段更多的字段来在响应中包含额外的内容。你可以使用populate参数来实现这一点。

🌐 Populating in the context of the Strapi REST API means including additional content with your response by returning more fields than the ones returned by default. You use the populate parameter to achieve this.

Info

在本指南中,示例是使用从 FoodAdvisor 示例应用附带的服务器查询的真实数据构建的。要自己测试示例,请设置 FoodAdvisor,在 /api/ 文件夹中启动服务器,并在发送查询之前确保为被查询的内容类型授予了适当的 find 权限。

本指南将详细解释以下用例:

🌐 The present guide will cover detailed explanations for the following use cases:

Info

填充多层通常被称为“深度填充”。

🌐 Populating several levels deep is often called "deep populate".

Advanced use case: Populating creator fields

除了在查询中使用 populate 参数的各种方法外,你还可以构建自定义控制器作为一种解决方法来填充创建者字段(例如,createdByupdatedBy)。这在专门的 如何填充创建者字段 指南中有说明。

🌐 In addition to the various ways of using the populate parameter in your queries, you can also build a custom controller as a workaround to populate creator fields (e.g., createdBy and updatedBy). This is explained in the dedicated How to populate creator fields guide.

填充所有关系和字段,深度为1级

🌐 Populate all relations and fields, 1 level deep

你可以通过单个查询返回所有关系、媒体字段、组件和动态区域。对于关系,这仅适用于一层深度,以防止性能问题和长时间的响应。

🌐 You can return all relations, media fields, components and dynamic zones with a single query. For relations, this will only work 1 level deep, to prevent performance issues and long response times.

要填充所有一级内容,请在查询中添加 populate=* 参数。

🌐 To populate everything 1 level deep, add the populate=* parameter to your query.

下图比较了 FoodAdvisor 示例应用在填充所有一级数据和未填充时返回的数据:

Diagram with populate use cases with FoodAdvisor data

让我们比较并解释使用和不使用此查询参数时会发生什么:

🌐 Let's compare and explain what happens with and without this query parameter:

示例:没有 populate

🌐 Example: Without populate

如果没有 populate 参数,对 /api/articlesGET 请求只会返回默认属性,不会返回任何媒体字段、关联、组件或动态区域。

🌐 Without the populate parameter, a GET request to /api/articles only returns the default attributes and does not return any media fields, relations, components or dynamic zones.

以下示例是来自 articles 内容类型的所有 4 个条目的完整响应。

🌐 The following example is the full response for all 4 entries from the articles content-types.

请注意,响应仅包含 titleslugcreatedAtupdatedAtpublishedAtlocale 字段,以及由 CKEditor 插件处理的文章字段内容(ckeditor_content,为简洁起见已截断):

🌐 Notice how the response only includes the title, slug, createdAt, updatedAt, publishedAt, and locale fields, and the field content of the article as handled by the CKEditor plugin (ckeditor_content, truncated for brevity):

示例请求

GET /api/articles

示例响应
{
"data": [
{
"id": 1,
"documentId": "t3q2i3v1z2j7o8p6d0o4xxg",
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": // truncated content
},
{
"id": 2,
"documentId": "k2r5l0i9g3u2j3b4p7f0sed",
"title": "What are chinese hamburgers and why aren't you eating them?",
"slug": "what-are-chinese-hamburgers-and-why-aren-t-you-eating-them",
"createdAt": "2021-11-11T13:33:19.948Z",
"updatedAt": "2023-06-01T14:32:50.984Z",
"publishedAt": "2022-09-22T12:36:48.312Z",
"locale": "en",
"ckeditor_content": // truncated content
},
{
"id": 3,
"documentId": "k6m6l9q0n6v9z2m3i0z5jah"
"title": "7 Places worth visiting for the food alone",
"slug": "7-places-worth-visiting-for-the-food-alone",
"createdAt": "2021-11-12T13:33:19.948Z",
"updatedAt": "2023-06-02T11:30:00.075Z",
"publishedAt": "2023-06-02T11:30:00.075Z",
"locale": "en",
"ckeditor_content": // truncated content
},
{
"id": 4,
"documentId": "d5m4b6z6g5d9e3v1k9n5gbn",
"title": "If you don't finish your plate in these countries, you might offend someone",
"slug": "if-you-don-t-finish-your-plate-in-these-countries-you-might-offend-someone",
"createdAt": "2021-11-15T13:33:19.948Z",
"updatedAt": "2023-06-02T10:59:35.148Z",
"publishedAt": "2022-09-22T12:35:53.899Z",
"locale": "en",
"ckeditor_content": // truncated content
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}

示例:使用 populate=*

🌐 Example: With populate=*

使用 populate=* 参数,对 /api/articlesGET 请求也会返回所有媒体字段、一级关系、组件和动态区域。

🌐 With the populate=* parameter, a GET request to /api/articles also returns all media fields, first-level relations, components and dynamic zones.

以下示例是来自 articles 内容类型的所有 4 个条目中的第一个条目的完整响应(id 为 2、3 和 4 的文章数据为了简洁而被截断)。

🌐 The following example is the full response for the first of all 4 entries from the articles content-types (the data from articles with ids 2, 3, and 4 is truncated for brevity).

向下滚动查看响应大小比没有使用 populate 时大得多。响应现在包括额外的字段(见高亮行),例如:

🌐 Scroll down to see that the response size is much bigger than without populate. The response now includes additional fields (see highlighted lines) such as:

  • image 媒体字段(存储关于文章封面 的所有信息,包括其所有不同格式),
  • blocks 动态区域和 seo 组件的一级字段,
  • category 关系及其字段,
  • 甚至还有一些关于以其他语言翻译的文章的信息,如 localizations 对象所示。
Tip

要填充深层嵌套的组件,请参阅填充组件部分。

🌐 To populate deeply nested components, see the populate components section.


示例请求

GET /api/articles?populate=*

示例响应
{
"data": [
{
"id": 1,
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": // truncated content
"image": {
"data": {
"id": 12,
"documentId": "o5d4b0l4p8l4o4k5n1l3rxa",
"name": "Basque dish",
"alternativeText": "Basque dish",
"caption": "Basque dish",
"width": 758,
"height": 506,
"formats": {
"thumbnail": {
"name": "thumbnail_https://4d40-2a01-cb00-c8b-1800-7cbb-7da-ea9d-2011.ngrok.io/uploads/basque_cuisine_17fa4567e0.jpeg",
"hash": "thumbnail_basque_cuisine_17fa4567e0_f033424240",
"ext": ".jpeg",
"mime": "image/jpeg",
"width": 234,
"height": 156,
"size": 11.31,
"path": null,
"url": "/uploads/thumbnail_basque_cuisine_17fa4567e0_f033424240.jpeg"
},
"medium": {
"name": "medium_https://4d40-2a01-cb00-c8b-1800-7cbb-7da-ea9d-2011.ngrok.io/uploads/basque_cuisine_17fa4567e0.jpeg",
"hash": "medium_basque_cuisine_17fa4567e0_f033424240",
"ext": ".jpeg",
"mime": "image/jpeg",
"width": 750,
"height": 501,
"size": 82.09,
"path": null,
"url": "/uploads/medium_basque_cuisine_17fa4567e0_f033424240.jpeg"
},
"small": {
"name": "small_https://4d40-2a01-cb00-c8b-1800-7cbb-7da-ea9d-2011.ngrok.io/uploads/basque_cuisine_17fa4567e0.jpeg",
"hash": "small_basque_cuisine_17fa4567e0_f033424240",
"ext": ".jpeg",
"mime": "image/jpeg",
"width": 500,
"height": 334,
"size": 41.03,
"path": null,
"url": "/uploads/small_basque_cuisine_17fa4567e0_f033424240.jpeg"
}
},
"hash": "basque_cuisine_17fa4567e0_f033424240",
"ext": ".jpeg",
"mime": "image/jpeg",
"size": 58.209999999999994,
"url": "/uploads/basque_cuisine_17fa4567e0_f033424240.jpeg",
"previewUrl": null,
"provider": "local",
"provider_metadata": null,
"createdAt": "2021-11-23T14:05:33.460Z",
"updatedAt": "2021-11-23T14:05:46.084Z"
}
}
},
"blocks": [
{
"id": 2,
"__component": "blocks.related-articles"
},
{
"id": 2,
"documentId": "w8r5k8o8v0t9l9e0d7y6vco",
"__component": "blocks.cta-command-line",
"theme": "primary",
"title": "Want to give a try to a Strapi starter?",
"text": "❤️",
"commandLine": "git clone https://github.com/strapi/nextjs-corporate-starter.git"
}
],
"seo": {
"id": 1,
"documentId": "h7c8d0u3i3q5v1j3j3r4cxf",
"metaTitle": "Articles - FoodAdvisor",
"metaDescription": "Discover our articles about food, restaurants, bars and more! - FoodAdvisor",
"keywords": "food",
"metaRobots": null,
"structuredData": null,
"metaViewport": null,
"canonicalURL": null
},
"category": {
"data": {
"id": 4,
"documentId": "t1t3d9k6n1k5a6r8l7f8rox",
"name": "European",
"slug": "european",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z"
}
},
"localizations": {
"data": [
{
"id": 10,
"documentId": "h7c8d0u3i3q5v1j3j3r4cxf",
"title": "Voici pourquoi il faut essayer la cuisine basque, selon un chef basque",
"slug": "voici-pourquoi-il-faut-essayer-la-cuisine-basque-selon-un-chef-basque",
"createdAt": "2021-11-18T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.606Z",
"publishedAt": "2022-09-22T13:00:00.069Z",
"locale": "fr-FR",
"ckeditor_content": // truncated content
}
]
}
}
},
{
"id": 2,
// truncated content
},
{
"id": 3,
// truncated content
},
{
"id": 4,
// truncated content
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}

填充特定的关系和字段

🌐 Populate specific relations and fields

你也可以通过明确定义要填充的内容来填充特定的关系和字段。这要求你知道要填充的字段和关系的名称。

🌐 You can also populate specific relations and fields, by explicitly defining what to populate. This requires that you know the name of fields and relations to populate.

通过这种方式填充的关系和字段可以有1级或多级深度。下图比较了当你填充1级深度2级深度时, FoodAdvisor 示例应用返回的数据:

Diagram with populate use cases with FoodAdvisor data

🤓 不同的填充策略但结果相似

根据你的内容结构,你可能会发现使用不同的查询以不同的方式呈现类似的数据。例如,FoodAdvisor 示例应用包含文章、类别和餐厅内容类型,它们以不同的方式相互关联。这意味着,如果你想在单个 GET 请求中获取关于这三种内容类型的数据,你有两个选择:

  • 查询文章并填充类别,同时填充类别与餐厅之间的嵌套关系(两级深度填充
  • 查询类别并填充文章和餐馆,因为类别与另外两种内容类型有一级关系(1级深

下图说明了这两种不同的策略:

🌐 The 2 different strategies are illustrated in the following diagram:

Diagram with populate use cases with FoodAdvisor data

作为对象填充与作为数组填充:使用交互式查询构建器

高级查询参数的语法手动构建可能相当复杂。我们建议你使用我们的交互式查询构建器工具来生成 URL。

🌐 The syntax for advanced query parameters can be quite complex to build manually. We recommend you use our interactive query builder tool to generate the URL.

使用这个工具,你将使用熟悉的(JavaScript)格式编写清晰且易读的请求,这应该有助于你理解不同查询和不同填充方式之间的差异。例如,深度填充 2 级意味着将 populate 用作对象,而深度填充 1 级的多个关系意味着将 populate 用作数组:

🌐 Using this tool, you will write clean and readable requests in a familiar (JavaScript) format, which should help you understand the differences between different queries and different ways of populating. For instance, populating 2 levels deep implies using populate as an object, while populating several relations 1 level deep implies using populate as an array:

填充为对象
(填充 1 个关系多个级别):

{
populate: {
category: {
populate: ['restaurants'],
},
},
}

填充为数组
(填充许多 1 层深的关系)

{
populate: [
'articles',
'restaurants'
],
}

为特定关系填充 1 级深度

🌐 Populate 1 level deep for specific relations

你可以使用 populate 参数作为数组来填充 1 层深度的特定关系。

🌐 You can populate specific relations 1 level deep by using the populate parameter as an array.

由于 REST API 使用 LHS bracket notation (即带方括号的 []),要填充一级参数的语法如下所示: | 填充多少关系 | 语法示例 ||-------------------------------|--------------------|| 仅 1 个关系 | populate[0]=a-relation-name || 多个关系 | populate[0]=relation-name&populate[1]=another-relation-name&populate[2]=yet-another-relation-name |

让我们比较并解释在向 FoodAdvisor 示例应用发送查询时,填充关系一级与不填充关系一级会发生什么:

示例:没有 populate

🌐 Example: Without populate

如果没有 populate 参数,向 /api/articlesGET 请求只会返回默认属性。

🌐 Without the populate parameter, a GET request to /api/articles only returns the default attributes.

以下示例是 articles 内容类型所有 4 个条目的完整响应。

🌐 The following example is the full response for all 4 entries from the articles content-type.

请注意,响应不包含任何媒体字段、关系、组件或动态区域:

🌐 Notice that the response does not include any media fields, relations, components or dynamic zones:


示例请求

GET /api/articles

示例响应
{
"data": [
{
"id": 1,
"documentId": "x2m0d7d9o4m2z3u2r2l9yes",
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
},
{
"id": 2,
"documentId": "k6m6l9q0n6v9z2m3i0z5jah",
"title": "What are chinese hamburgers and why aren't you eating them?",
"slug": "what-are-chinese-hamburgers-and-why-aren-t-you-eating-them",
"createdAt": "2021-11-11T13:33:19.948Z",
"updatedAt": "2023-06-01T14:32:50.984Z",
"publishedAt": "2022-09-22T12:36:48.312Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
},
{
"id": 3,
"documentId": "o5d4b0l4p8l4o4k5n1l3rxa",
"title": "7 Places worth visiting for the food alone",
"slug": "7-places-worth-visiting-for-the-food-alone",
"createdAt": "2021-11-12T13:33:19.948Z",
"updatedAt": "2023-06-02T11:30:00.075Z",
"publishedAt": "2023-06-02T11:30:00.075Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
},
{
"id": 4,
"documentId": "t3q2i3v1z2j7o8p6d0o4xxg",
"title": "If you don't finish your plate in these countries, you might offend someone",
"slug": "if-you-don-t-finish-your-plate-in-these-countries-you-might-offend-someone",
"createdAt": "2021-11-15T13:33:19.948Z",
"updatedAt": "2023-06-02T10:59:35.148Z",
"publishedAt": "2022-09-22T12:35:53.899Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}
}

示例:使用 populate[0]=category

🌐 Example: With populate[0]=category

在请求中添加 populate[0]=category 后,我们明确要求包含一些关于 category 的信息,category 是一个关系字段,用于链接 articlescategories 内容类型。

🌐 With populate[0]=category added to the request, we explicitly ask to include some information about category, which is a relation field that links the articles and the categories content-types.

以下示例是 articles 内容类型所有 4 个条目的完整响应。

🌐 The following example is the full response for all 4 entries from the articles content-type.

请注意,响应现在包含每篇文章的 category 字段的额外数据(见高亮行):

🌐 Notice that the response now includes additional data with the category field for each article (see highlighted lines):

示例请求

GET /api/articles?populate[0]=category

示例响应
{
"data": [
{
"id": 1,
"documentId": "w8r5k8o8v0t9l9e0d7y6vco",
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"category": {
"data": {
"id": 4,
"documentId": "u6x8u7o7j5q1l5y3t8j9yxi",
"name": "European",
"slug": "european",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z"
}
}
},
{
"id": 2,
"documentId": "k6m6l9q0n6v9z2m3i0z5jah",
"title": "What are chinese hamburgers and why aren't you eating them?",
"slug": "what-are-chinese-hamburgers-and-why-aren-t-you-eating-them",
"createdAt": "2021-11-11T13:33:19.948Z",
"updatedAt": "2023-06-01T14:32:50.984Z",
"publishedAt": "2022-09-22T12:36:48.312Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"category": {
"data": {
"id": 13,
"documentId": "x2m0d7d9o4m2z3u2r2l9yes",
"name": "Chinese",
"slug": "chinese",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z"
}
}
},
{
"id": 3,
"title": "7 Places worth visiting for the food alone",
"slug": "7-places-worth-visiting-for-the-food-alone",
"createdAt": "2021-11-12T13:33:19.948Z",
"updatedAt": "2023-06-02T11:30:00.075Z",
"publishedAt": "2023-06-02T11:30:00.075Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"category": {
"data": {
"id": 3,
"documentId": "h7c8d0u3i3q5v1j3j3r4cxf",
"name": "International",
"slug": "international",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z"
}
}
},
{
"id": 4,
"documentId": "t1t3d9k6n1k5a6r8l7f8rox",
"title": "If you don't finish your plate in these countries, you might offend someone",
"slug": "if-you-don-t-finish-your-plate-in-these-countries-you-might-offend-someone",
"createdAt": "2021-11-15T13:33:19.948Z",
"updatedAt": "2023-06-02T10:59:35.148Z",
"publishedAt": "2022-09-22T12:35:53.899Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"category": {
"data": {
"id": 3,
"documentId": "u6x8u7o7j5q1l5y3t8j9yxi",
"name": "International",
"slug": "international",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z"
}
}
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}

为特定关系填充多层数据

🌐 Populate several levels deep for specific relations

你还可以填充特定的多层关系。例如,当你填充一个关系,而该关系本身又填充另一个关系时,你就是在填充两层深的关系。在本指南中介绍的示例就是填充两层深的关系。

🌐 You can also populate specific relations several levels deep. For instance, when you populate a relation which itself populates another relation, you are populating 2 levels deep. Populating 2 levels deep is the example covered in this guide.

Caution

可以填充的层级数量没有限制。然而,填充的层级越深,请求执行所需的时间就越长。

🌐 There is no limit on the number of levels that can be populated. However, the deeper the populates, the more the request will take time to be performed.

由于 REST API 使用 LHS bracket notation(即使用方括号 []),例如,如果你想填充嵌套在另一个关系中的关系,参数语法如下所示:

populate[first-level-relation-to-populate][populate][0]=second-level-relation-to-populate

Tip

高级查询参数的语法手动构建起来可能相当复杂。我们建议你使用我们的交互式查询构建器工具来生成 URL。例如,以下示例中使用的 /api/articles?populate[category][populate][0]=restaurants URL 是通过使用我们的工具将以下对象转换生成的:

🌐 The syntax for advanced query parameters can be quite complex to build manually. We recommend you use our interactive query builder tool to generate the URL. For instance, the /api/articles?populate[category][populate][0]=restaurants URL used in the following examples has been generated by converting the following object using our tool:

{
populate: {
category: {
populate: ['restaurants'],
},
},
}

FoodAdvisor 示例应用包含内容类型之间的各种级别的关系。例如:

  • 一个 article 内容类型包括与 category 内容类型的关系,
  • 但是 category 也可以分配给任何 restaurant 内容类型。

通过对 /api/articles 发出一次 GET 请求并使用适当的 populate 参数,你可以同时返回关于文章、餐厅和类别的信息。

🌐 With a single GET request to /api/articles and the appropriate populate parameters, you can return information about articles, restaurants, and categories simultaneously.

让我们比较并解释在向 FoodAdvisor 发送查询时,populate[0]=category(1 级深度)和 populate[category][populate][0]=restaurants(2 级深度)返回的响应:

🌐 Let's compare and explain the responses returned with populate[0]=category (1 level deep) and populate[category][populate][0]=restaurants (2 levels deep) when sending queries to FoodAdvisor:

示例:具有 1 级深度的人口

🌐 Example: With 1-level deep population

当我们只填充一层深度时,查询与文章相关的类别,我们可以得到以下示例响应(高亮行显示 category 关系字段):

🌐 When we only populate 1 level deep, asking for the categories associated to articles, we can get the following example response (highlighted lines show the category relations field):

示例请求

GET /api/articles?populate[0]=category

示例响应
{
"data": [
{
"id": 1,
"documentId": "9ih6hy1bnma3q3066kdwt3",
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"category": {
"data": {
"id": 4,
"name": "European",
"slug": "european",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z"
}
}
},
{
"id": 2,
"documentId": "sen6qfgxcac13pwchf8xbu",
"title": "What are chinese hamburgers and why aren't you eating them?",
"slug": "what-are-chinese-hamburgers-and-why-aren-t-you-eating-them",
"createdAt": "2021-11-11T13:33:19.948Z",
"updatedAt": "2023-06-01T14:32:50.984Z",
"publishedAt": "2022-09-22T12:36:48.312Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"category": {
"data": {
"id": 13,
"documentId": "r3rhzcxd7gjx07vkq3pia5",
"name": "Chinese",
"slug": "chinese",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z"
}
}
},
{
"id": 3,
"documentId": "s9uu7rkukhfcsmj2e60b67",
"title": "7 Places worth visiting for the food alone",
"slug": "7-places-worth-visiting-for-the-food-alone",
"createdAt": "2021-11-12T13:33:19.948Z",
"updatedAt": "2023-06-02T11:30:00.075Z",
"publishedAt": "2023-06-02T11:30:00.075Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"category": {
"data": {
"id": 3,
"documentId": "4sevz15w6bdol6y4t8kblk",
"name": "International",
"slug": "international",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z"
}
}
},
{
"id": 4,
"documentId": "iy5ifm3xj8q0t8vlq6l23h",
"title": "If you don't finish your plate in these countries, you might offend someone",
"slug": "if-you-don-t-finish-your-plate-in-these-countries-you-might-offend-someone",
"createdAt": "2021-11-15T13:33:19.948Z",
"updatedAt": "2023-06-02T10:59:35.148Z",
"publishedAt": "2022-09-22T12:35:53.899Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"category": {
"data": {
"id": 3,
"documentId": "0eor603u8qej933maphdv3",
"name": "International",
"slug": "international",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z"
}
}
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}

示例:具有两级深度的人口

🌐 Example: With 2-level deep population

当我们填充 2 层深度时,询问与文章相关的类别,以及与这些类别相关的餐馆,我们可以得到以下示例响应。

🌐 When we populate 2 levels deep, asking for the categories associated to articles, but also for restaurants associated to these categories, we can get the following example response.

请注意,我们现在在 category 关系内的响应中包含了 restaurants 关系字段(见高亮行):

🌐 Notice that we now have the restaurants relation field included with the response inside the category relation (see highlighted lines):

示例请求

GET /api/articles?populate[category][populate][0]=restaurants

示例响应
{{
"data": [
{
"id": 1,
"documentId": "iy5ifm3xj8q0t8vlq6l23h",
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"category": {
"data": {
"id": 4,
"name": "European",
"slug": "european",
"createdAt": "2021-11-09T13:33:20.123Z",
"updatedAt": "2021-11-09T13:33:20.123Z",
"restaurants": {
"data": [
{
"id": 1,
"documentId": "ozlqrdxpnjb7wtvf6lp74v",
"name": "Mint Lounge",
"slug": "mint-lounge",
"price": "p3",
"createdAt": "2021-11-09T14:07:47.125Z",
"updatedAt": "2021-11-23T16:41:30.504Z",
"publishedAt": "2021-11-23T16:41:30.501Z",
"locale": "en"
},
{
"id": 9,
// truncated content
},
{
"id": 10,
// truncated content
},
{
"id": 12,
// truncated content
},
{
"id": 21,
// truncated content
},
{
"id": 26,
// truncated content
}
]
}
}
}
},
{
"id": 2,
// truncated content
},
{
"id": 3,
// truncated content
},
{
"id": 4,
// truncated content
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}

填充组件

🌐 Populate components

默认情况下,组件和动态区域不包含在响应中,你需要显式填充每个动态区域、组件及其嵌套组件。

🌐 Components and dynamic zones are not included in responses by default and you need to explicitly populate each dynamic zones, components, and their nested components.

由于 REST API 使用 LHS bracket notation(即带方括号的 []),你需要在 populate 数组中传递所有元素。嵌套字段也可以传递,参数语法可能如下所示:

populate[0]=a-first-field&populate[1]=a-second-field&populate[2]=a-third-field&populate[3]=a-third-field.a-nested-field&populate[4]=a-third-field.a-nested-component.a-nested-field-within-the-component

Tip

高级查询参数的语法手动构建起来可能相当复杂。我们建议你使用我们的交互式查询构建器工具来生成 URL。例如,以下示例中使用的 /api/articles?populate[0]=seo&populate[1]=seo.metaSocial&populate[2]=seo.metaSocial.image URL 是通过使用我们的工具将以下对象转换生成的:

🌐 The syntax for advanced query parameters can be quite complex to build manually. We recommend you use our interactive query builder tool to generate the URL. For instance, the /api/articles?populate[0]=seo&populate[1]=seo.metaSocial&populate[2]=seo.metaSocial.image URL used in the following examples has been generated by converting the following object using our tool:

{
populate: [
'seoData',
'seoData.sharedImage',
'seoData.sharedImage.media',
],
},

FoodAdvisor 示例应用包括各种组件,甚至包括嵌套在其他组件中的组件。例如:

  • 一个 article 内容类型包括一个 seo 组件 1
  • seo 组件包含一个嵌套的、可重复的 metaSocial 组件 2,
  • metaSocial 组件本身有几个字段,包括一个 image 媒体字段 3

FoodAdvisor's SEO component structure in the Content-Type Builder

默认情况下,这些字段或组件都不会包含在对 /api/articlesGET 请求响应中。但通过适当的 populate 参数,你可以在一次请求中返回它们所有。

🌐 By default, none of these fields or components are included in the response of a GET request to /api/articles. But with the appropriate populate parameters, you can return all of them in a single request.

让我们比较并解释通过 populate[0]=seo(一级组件)和 populate[0]=seo&populate[1]=seo.metaSocial(嵌套在一级组件中的二级组件)返回的响应:

🌐 Let's compare and explain the responses returned with populate[0]=seo (1st level component) and populate[0]=seo&populate[1]=seo.metaSocial (2nd level component nested within the 1st level component):

示例:仅第一级组件

🌐 Example: Only 1st level component

当我们只填充 seo 组件时,我们只深入 1 级,并且可以得到以下示例响应。高亮的行显示了 seo 组件。

🌐 When we only populate the seo component, we go only 1 level deep, and we can get the following example response. Highlighted lines show the seo component.

注意没有提到嵌套在 seo 组件中的 metaSocial 组件:

🌐 Notice there's no mention of the metaSocial component nested within the seo component:

示例请求

GET /api/articles?populate[0]=seo

示例响应
{
"data": [
{
"id": 1,
"documentId": "md60m5cy3dula5g87x1uar",
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"seo": {
"id": 1,
"documentId": "kqcwhq6hes25kt9ebj8x7j",
"metaTitle": "Articles - FoodAdvisor",
"metaDescription": "Discover our articles about food, restaurants, bars and more! - FoodAdvisor",
"keywords": "food",
"metaRobots": null,
"structuredData": null,
"metaViewport": null,
"canonicalURL": null
}
},
{
"id": 2,
// truncated content
},
{
"id": 3,
// truncated content
},
{
"id": 4,
// truncated content
},
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}

示例:一级组件和二级组件

🌐 Example: 1st level and 2nd level component

当我们填充两层深度时,同时请求 seo 组件和嵌套在 seo 内的 metaSocial 组件,我们可以得到以下示例响应。

🌐 When we populate 2 levels deep, asking both for the seo component and the metaSocial component nested inside seo, we can get the following example response.

请注意,我们现在在响应中包含了 metaSocial 组件相关的数据(见高亮行):

🌐 Notice that we now have the metaSocial component-related data included with the response (see highlighted lines):

示例请求

GET /api/articles?populate[0]=seo&populate[1]=seo.metaSocial

示例响应
{
"data": [
{
"id": 1,
"documentId": "c2imt19iywk27hl2ftph7s",
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"seo": {
"id": 1,
"documentId": "e8cnux5ejxyqrejd5addfv",
"metaTitle": "Articles - FoodAdvisor",
"metaDescription": "Discover our articles about food, restaurants, bars and more! - FoodAdvisor",
"keywords": "food",
"metaRobots": null,
"structuredData": null,
"metaViewport": null,
"canonicalURL": null,
"metaSocial": [
{
"id": 1,
"documentId": "ks7xsp9fewoi0qljcz9qa0",
"socialNetwork": "Facebook",
"title": "Browse our best articles about food and restaurants ",
"description": "Discover our articles about food, restaurants, bars and more!"
}
]
}
},
{
"id": 2,
// truncated content
},
{
"id": 3,
// truncated content
},
{
"id": 4,
// truncated content
},
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}

填充动态区域

🌐 Populate dynamic zones

动态区域本质上是高度动态的内容结构。要填充动态区域及其内容,你需要明确地定义用响应填充什么内容。

🌐 Dynamic zones are highly dynamic content structures by essence. To populate dynamic zones and their content, you need to explicitly define what to populate with the response.

为此,你可以使用 on 属性定义每个组件的填充查询。

🌐 To do so, you can define per-component populate queries using the on property.

例如,在 FoodAdvisor 示例应用中:

  • blocks 动态区域存在于 article 内容类型 1 中。
  • 动态区域包括3个不同的组件:relatedArticles 2faq 3CtaCommandLine 4。所有组件都有不同的内容结构,包含各种字段。
  • relatedArticles 组件与文章内容类型具有 articles 关系 5

FoodAdvisor's 'blocks' dynamic zone structure in the Content-Type Builder

默认情况下,对 /api/articlesGET 请求的响应中不会包含任何深层嵌套的字段或关系。通过使用适当的 populate 参数并应用详细的填充策略,你可以精确返回所需的数据。

🌐 By default, none of the deeply nested fields or relations are included in the response of a GET request to /api/articles. With the appropriate populate parameters and by applying a detailed population strategy, you can return precisely the data you need.

Tip

高级查询参数的语法手动构建起来可能相当复杂。我们建议你使用我们的交互式查询构建器工具来生成 URL。例如,以下示例中使用的 /api/articles?populate[blocks][on][blocks.related-articles][populate][articles][populate][0]=image&populate[blocks][on][blocks.cta-command-line][populate]=* URL 是通过使用我们的工具将以下对象转换生成的:

🌐 The syntax for advanced query parameters can be quite complex to build manually. We recommend you use our interactive query builder tool to generate the URL. For instance, the /api/articles?populate[blocks][on][blocks.related-articles][populate][articles][populate][0]=image&populate[blocks][on][blocks.cta-command-line][populate]=* URL used in the following example has been generated by converting the following object using our tool:

{
populate: {
blocks: { // asking to populate the blocks dynamic zone
on: { // using a detailed population strategy to explicitly define what you want
'blocks.related-articles': {
populate: {
'articles': {
populate: ['image']
}
}
},
'blocks.cta-command-line': {
populate: '*'
}
},
},
},
}

让我们通过共享人口策略和详细人口策略的一些示例来比较和解释返回的响应:

🌐 Let's compare and explain the responses returned with some examples of a shared population strategy and a detailed population strategy:

例子

🌐 Example

当我们填充 blocks 动态区域时,我们会明确规定要填充哪些数据。

🌐 When we populate the blocks dynamic zone, we explicitly define which data to populate.

在以下示例响应中,高亮的行显示:

🌐 In the following example response, highlighted lines show that:

  • 我们深入填充 relatedArticles 组件的 articles 关系,甚至相关文章的 image 媒体字段。
  • 但是因为我们只要求为 CtaCommandLine 组件填充所有内容,并且没有为 faq 组件定义任何内容,所以没有返回来自 faq 组件的数据。
带有详细人口的示例请求

GET /api/articles?populate[blocks][on][blocks.related-articles][populate][articles][populate][0]=image&populate[blocks][on][blocks.cta-command-line][populate]=*

带有人口详细信息的示例响应
{
"data": [
{
"id": 1,
"documentId": "it9bbhcgc6mcfsqas7h1dp",
"title": "Here's why you have to try basque cuisine, according to a basque chef",
"slug": "here-s-why-you-have-to-try-basque-cuisine-according-to-a-basque-chef",
"createdAt": "2021-11-09T13:33:19.948Z",
"updatedAt": "2023-06-02T10:57:19.584Z",
"publishedAt": "2022-09-22T09:30:00.208Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"blocks": [
{
"id": 2,
"documentId": "e8cnux5ejxyqrejd5addfv",
"__component": "blocks.related-articles",
"articles": {
"data": [
{
"id": 2,
"documentId": "wkgojrcg5bkz8teqx1foz7",
"title": "What are chinese hamburgers and why aren't you eating them?",
"slug": "what-are-chinese-hamburgers-and-why-aren-t-you-eating-them",
"createdAt": "2021-11-11T13:33:19.948Z",
"updatedAt": "2023-06-01T14:32:50.984Z",
"publishedAt": "2022-09-22T12:36:48.312Z",
"locale": "en",
"ckeditor_content": "…", // truncated content
"image": {
"data": {
// …
}
}
}
},
{
"id": 3,
// …
},
{
"id": 4,
// …
}
]
}
},
{
"id": 2,
"__component": "blocks.cta-command-line",
"theme": "primary",
"title": "Want to give a try to a Strapi starter?",
"text": "❤️",
"commandLine": "git clone https://github.com/strapi/nextjs-corporate-starter.git"
}
]
},
{
"id": 2,
// …
},
{
"id": 3,
"documentId": "z5jnfvyuj07fogzh1kcbd3",
"title": "7 Places worth visiting for the food alone",
"slug": "7-places-worth-visiting-for-the-food-alone",
"createdAt": "2021-11-12T13:33:19.948Z",
"updatedAt": "2023-06-02T11:30:00.075Z",
"publishedAt": "2023-06-02T11:30:00.075Z",
"locale": "en",
"ckeditor_content": "…", // … truncated content
"blocks": [
{
"id": 1,
"documentId": "ks7xsp9fewoi0qljcz9qa0",
"__component": "blocks.related-articles",
"articles": {
// …
}
},
{
"id": 1,
"documentId": "c2imt19iywk27hl2ftph7s",
"__component": "blocks.cta-command-line",
"theme": "secondary",
"title": "Want to give it a try with a brand new project?",
"text": "Up & running in seconds 🚀",
"commandLine": "npx create-strapi-app my-project --quickstart"
}
]
},
{
"id": 4,
// …
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 4
}
}
}