Skip to main content

不推荐使用文档服务 API 更新可重复使用的组件

🌐 Updating repeatable components with the Document Service API is not recommended

Page summary:

在 Strapi 5 中,文档的草稿和已发布版本使用不同的数字组件 id。通常,从已发布的响应中重用 id 来更新草稿会失败。建议在可用持久组件身份推出之前,要么替换整个组件数组,要么在草稿 ID 上进行编辑。

🌐 In Strapi 5, draft and published versions of a document use different numeric component ids. Reusing an id from a published response to update the draft usually fails. Prefer replacing the full component array (or editing against draft ids) until a durable component identity ships.

在 Strapi 5 中,不推荐通过重复使用已发布 API 响应中的组件 id 来更新可重复组件,因为草稿与发布模式会影响 Document Service API 的交互。

🌐 In Strapi 5, it's not recommended to update repeatable components by reusing component ids from published API responses, because of how Draft & Publish interacts with the Document Service API.

此页面是重大更改数据库的一部分,提供关于重大更改的信息以及从 Strapi v4 迁移到 Strapi 5 的附加说明。

🌐 This page is part of the breaking changes database and provides information about the breaking change and additional instructions to migrate from Strapi v4 to Strapi 5.

 Is this breaking change affecting plugins?Yes
 Is this breaking change automatically handled by a codemod?No

重大变更描述​

🌐 Breaking change description

在 Strapi v4 中

你可以通过传递它的数字 id 来部分更新可重复的组件。

🌐 You could partially update a repeatable component by passing its numeric id.

在 Strapi 5 中

文档使用稳定的 documentId,但嵌套组件仍然使用状态本地数字 id。发布会创建新的组件行,因此同一模块的草稿和已发布版本有不同的 id。你不能把已发布的组件 id 当作文档级别的标识符。

🌐 Documents use a stable documentId, but nested components still use status-local numeric ids. Publishing creates new component rows, so the draft and published versions of the same block have different ids. You cannot treat a published component id like a document-level identifier.

迁移​

🌐 Migration

本节重新组合了有关引入的重大更改的有用说明和程序。

🌐 This section regroups useful notes and procedures about the introduced breaking change.

注意​

🌐 Notes

启用草稿和发布后,典型的内容 API 流程是这样的:

🌐 With Draft & Publish enabled, a typical Content API flow looks like this:

// Request: Content API returns the published version by default
GET /api/articles

// Response (published)
{
data: {
documentId: '…',
components: [
{ id: 2, name: 'component-1' },
{ id: 4, name: 'component-2' },
],
},
}

用那些已发布的 id 更新会生成草稿,它有不同的组件行 ID:

🌐 Updating with those published ids writes the draft, which has different component row ids:

PUT /api/articles/{documentId}
{
data: {
components: [
{ id: 2, name: 'component-1-updated' }, // published id, usually wrong for draft
],
},
}

这通常会因为 id: 2 没有链接到草稿条目而报错,比如 Some of the provided components in components are not related to the entity。这和 组件和动态区域在 REST API 响应中不会返回 id 有关。

🌐 This often fails with an error such as Some of the provided components in components are not related to the entity, because id: 2 is not linked to the draft entry. This is related to the fact that components and dynamic zones do not return an id in REST API responses.

文档服务 在读取/更新时默认使用草稿,所以当你使用草稿组件 ID 时,id 可以在那儿(以及内容管理器里)进行原地更新。陷阱在于混合已发布的 ID 和草稿写入。

🌐 The Document Service defaults to the draft on read/update, so in-place updates by id can work there (and in the Content Manager) when you use draft component ids. The trap is mixing published ids with draft writes.

🌐 Recommended workarounds

在有了持久的嵌套身份之前,使用以下其中一种。

🌐 Until a durable nested identity is available, use one of the following.

1. 替换整个组件数组(内容 API 推荐)​

🌐 1. Replace the full component array (preferred for Content API)

省略组件 id 并发送完整的所需列表。Strapi 会在草稿上重新创建这些组件。这是对只看到已发布数据的 REST/GraphQL 客户端而言,支持且稳定的方法:

🌐 Omit component ids and send the complete desired list. Strapi recreates the components on the draft. This is the supported, non-fragile approach for REST/GraphQL clients that only see published data:

// Document Service
await strapi.documents('api::article.article').update({
documentId,
data: {
components: [
{ name: 'component-1-updated' },
{ name: 'component-2' },
],
},
});
// REST Content API
PUT /api/articles/{documentId}
{
"data": {
"components": [
{ "name": "component-1-updated" },
{ "name": "component-2" }
]
}
}
Tip

包括你想保留的每个组件。数组中遗漏的条目会从草稿中删除。

🌐 Include every component you want to keep. Entries omitted from the array are removed from the draft.

2. 针对草稿组件ID进行编辑(文档服务 / 管理风格)​

🌐 2. Edit against draft component ids (Document Service / admin-style)

如果你能控制后端(自定义路由、脚本、文档服务),加载草稿,然后使用这些ID进行更新:

🌐 If you control the backend (custom routes, scripts, Document Service), load the draft, then update using those ids:

const draft = await strapi.documents('api::article.article').findOne({
documentId,
status: 'draft',
populate: ['components'],
});

await strapi.documents('api::article.article').update({
documentId,
data: {
components: draft.components.map((component) =>
component.id === targetDraftId
? { id: component.id, name: 'component-1-updated' }
: { id: component.id, name: component.name }
),
},
});

不要在这个模式中重用默认内容 API GET(已发布)的 ID。

🌐 Do not reuse ids from a default Content API GET (published) for this pattern.

3. 草稿和发布已禁用​

🌐 3. Draft & Publish disabled

如果内容类型上禁用了草稿和发布,就只有一个组件行集,所以基于 ID 的更新问题不大。不过,为了让客户端代码更简单,还是建议使用整个数组替换的方式。

🌐 If Draft & Publish is disabled on the content-type, there is only one component row set, so id-based updates are less problematic. Prefer the full-array replace pattern anyway for simpler client code.