Azure Cosmos DB 中的部分文档更新

适用范围: NoSQL

Azure Cosmos DB 部分文档更新功能(也称为修补程序 API)提供了一种在容器中修改文档的便捷方法。 目前,若要更新文档,客户端需要读取文档,执行乐观并发控制检查(如有必要),在本地更新文档,然后将其作为整个文档替换 API 调用通过网络发送。

部分文档更新功能可显著改善此体验。 客户端仅发送文档中修改过的属性/字段,而不进行完整的文档替换操作。 此功能的主要优点包括:

  • 提高开发人员的工作效率:提供方便的 API,以便于使用并能够有条件地更新文档。
  • 性能改进:在客户端上避免额外的 CPU 周期,减少端到端延迟和网络带宽。
  • 多区域写入:通过对同一文档中的离散路径进行部分更新,支持自动和透明的冲突解决方案。

注释

部分文档更新作基于 JSON 修补程序 RFC。 路径中的属性名称需要分别转义~字符和/字符~0~1

目标 JSON 文档示例:

{
  "id": "eeeeeeee-4444-5555-6666-ffffffffffff",
  "name": "R-410 Road Bicycle",
  "price": 455.95,
  "inventory": {
    "quantity": 15
  },
  "used": false,
  "categoryId": "road-bikes",
  "tags": ["r-series"]
}

JSON 修补文档:

[
  { "op": "add", "path": "/color", "value": "silver" },
  { "op": "remove", "path": "/used" },
  { "op": "set", "path": "/price", "value": 355.45 }
  { "op": "incr", "path": "/inventory/quantity", "value": 10 },
  { "op": "add", "path": "/tags/-", "value": "featured-bikes" },
  { "op": "move", "from": "/color", "path": "/inventory/color" }
]

生成的 JSON 文档:

{
  "id": "eeeeeeee-4444-5555-6666-ffffffffffff",
  "name": "R-410 Road Bicycle",
  "price": 355.45,
  "inventory": {
    "quantity": 25,
    "color": "silver"
  },
  "categoryId": "road-bikes",
  "tags": ["r-series", "featured-bikes"]
}

支持的操作

此表总结了此功能支持的操作。

注释

目标路径 是指 JSON 文档中的位置。

操作类型 DESCRIPTION
添加 Add 执行以下操作之一,具体取决于目标路径:
• 如果目标路径指定了一个不存在的元素,则添加该元素。
• 如果目标路径指定了一个已存在的元素,则替换其值。
• 如果目标路径是有效的数组索引,则将新元素插入到指定索引处的数组中。 这会将现有元素移到新元素之后。
• 如果指定的索引等于数组的长度,它会向数组追加一个元素。 除了指定索引,也可以使用 - 字符。 它还会导致向数组追加元素。
注意:指定的索引大于数组长度时会导致错误。
设置 Set Add类似于数组数据类型除外。 如果目标路径是有效的数组索引,则更新该索引处的现有元素。
替换 Replace 类似于 Set 只遵循 严格的 仅替换语义。 如果目标路径指定了不存在的元素或数组,则会导致错误。
删除 Remove 执行以下操作之一,具体取决于目标路径:
• 如果目标路径指定了一个不存在的元素,则会导致错误。
• 如果目标路径指定了一个已存在的元素,则将其删除。
• 如果目标路径是一个数组索引,则将其删除并将指定索引上方的任何元素都回移一个位置。
注意:如果指定的索引等于或大于数组长度,将导致错误。
增量 此运算符按指定的值增加字段。 它可以接受正值和负值。 如果字段不存在,它会创建字段并将其设置为指定值。
移动 此运算符删除指定位置的值,并将其添加到目标位置。 操作对象必须包含一个“from”成员,该成员是包含 JSON 指针值的字符串,其中的指针值引用目标文档中要从中移动值的位置。 必须存在“发件人”位置才能使作成功。 如果“path”位置建议不存在的对象,它将创建该对象并将值设置为等于“from”位置的值。
•如果“path”位置建议已存在的对象,它将“path”位置的值替换为“from”位置的值
•“path”属性不能是“from”JSON 位置的 JSON 子级。

支持的模式

部分文档更新功能支持以下运算模式。 有关代码示例 ,请参阅入门 文档。

  • 单个文档补丁:可以根据文档 ID 和分区键对单个文档进行修补。 可以对单个文档执行多个修补操作。 最大限制为 10 次操作。

  • 多文档补丁:同一分区键内的多个文档可以作为事务的一部分进行修补。 仅当所有操作均按所述顺序成功完成时,此多文档事务才会提交。 如果任何操作失败,将回滚整个事务。

  • 条件更新:对于前面提到的模式,还可以添加类似于 SQL 的筛选器谓词(例如 from c where c.taskNum = 3),以便在不满足谓词中指定的前置条件时作失败。

  • 也可使用支持的 SDK 的批量 API 对多个文档执行一个或多个修补操作。

相似性和差异性

我们来比较一下支持的模式之间的相似之处和差别。

添加与设置

Set 作类似于 Add 除以下所有数据类型外 Array的所有数据类型。 在任何(有效)索引处执行 Add 操作后,都会在指定索引处添加一个元素,并且数组中的任何现有元素最终都会移到该元素之后。 此行为与更新指定索引处的现有元素的 Set 操作相反。

添加与替换

如果该属性尚不存在(包括Array数据类型),该Add作将添加一个属性。 如果属性不存在,则 Replace 操作失败(也适用于 Array 数据类型)。

设置与替换

如果属性尚不存在,则 Set 此作会添加一个属性(除非存在属性 Array)。 如果属性不存在,则 Replace 操作失败(也适用于 Array 数据类型)。

注释

如果用户希望某些属性始终存在并且允许断言/强制执行该属性,则 Replace 是一个不错的选项。

部分文档更新的 REST API 参考

Azure Cosmos DB REST API 提供对 Azure Cosmos DB 资源的编程访问权限,以创建、查询和删除数据库、文档集合和文档。 除了对集合中的 JSON 文档执行插入、替换、删除、读取、枚举和查询操作外,还可以对部分文档更新操作使用 PATCH HTTP 方法。 请参阅 Azure Cosmos REST API 参考了解详细信息。

例如,下面是使用部分文档更新的作的请求。set

PATCH https://querydemo.documents.azure.cn/dbs/FamilyDatabase/colls/FamilyContainer/docs/Andersen.1 HTTP/1.1
x-ms-documentdb-partitionkey: ["Andersen"]
x-ms-date: Tue, 29 Mar 2016 02:28:29 GMT
Authorization: type%3dmaster%26ver%3d1.0%26sig%3d92WMAkQv0Zu35zpKZD%2bcGSH%2b2SXd8HGxHIvJgxhO6%2fs%3d
Content-Type:application/json_patch+json
Cache-Control: no-cache
User-Agent: Microsoft.Azure.DocumentDB/2.16.12
x-ms-version: 2015-12-16
Accept: application/json
Host: querydemo.documents.azure.cn
Cookie: x-ms-session-token#0=602; x-ms-session-token=602
Content-Length: calculated when request is sent
Connection: keep-alive
{
  "operations": [
    {
      "op": "set",
      "path": "/Parents/0/FamilyName",
      "value": "Bob"
    }
  ]
}

文档级与路径级冲突解决

如果 Azure Cosmos DB 帐户配置了多个写入区域, 则冲突和冲突解决策略 适用于文档级别,最后一次写入 Wins (LWW) 是默认冲突解决策略。 对于部分文档更新,跨多个区域的修补操作会检测和解决更详细的路径级别上的冲突。

通过示例可以更好地理解冲突解决。

假设 Azure Cosmos DB 中有以下文档:

{
  "id": 1,
  "name": "John Doe",
  "email": "jdoe@contoso.com",
  "phone": ["12345", "67890"],
  "level": "gold"
}

不同客户端跨不同区域并发发出修补操作:

  • Set 属性 /level 为白金
  • Remove/phone 67890

显示并发多区域部分更新作中的冲突解决的关系图。

由于修补请求是针对文档中的非冲突路径发出的,因此这些请求会以透明方式自动解决冲突(与文档级别的“以最后写入者为准”相反)。

客户端在冲突解决后看到以下文档:

{
  "id": 1,
  "name": "John Doe",
  "email": "jdoe@contoso.com",
  "phone": ["12345"],
  "level": "platinum"
}

注释

如果在多个区域中同时修补文档的同一属性,则应用常规的冲突解决策略

更改源

Azure Cosmos DB 中的更改源侦听容器中是否有任何更改,然后输出已更改的文档。 使用更改源,可看到文档的所有更新,包括部分和完整文档更新。 处理来自更改源中的项时,即使更新是修补操作的结果,也会返回完整的文档。

有关 Azure Cosmos DB 中的更改源的详细信息,请参阅 Azure Cosmos DB 中的更改源

后续步骤