你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
Azure Cosmos DB 部分文档更新入门
适用范围: NoSQL
本文提供的示例说明了如何将部分文档更新与 .NET、Java 和 Node SDK 结合使用。 它还描述了可能会遇到的常见错误。
本文链接到以下场景的代码示例:
- 运行单个补丁操作
- 合并多个补丁操作
- 基于筛选器谓词使用条件补丁语法
- 作为事务的一部分运行补丁操作
先决条件
- 现有的 Azure Cosmos DB 帐户。
- 如果你有 Azure 订阅,请创建一个新帐户。
- 如果还没有 Azure 订阅,可以在开始前创建一个免费帐户。
- 或者,可以在提交之前免费试用 Azure Cosmos DB。
从版本 3.23.0 开始,提供对 Azure Cosmos DB .NET v3 SDK 中部分文档更新(补丁 API)的支持。 可以从 NuGet 库 中下载该内容。
注意
在 GitHub 上的 .NET v3 示例存储库 中查找部分文档更新的完整示例。
运行单个补丁操作:
ItemResponse<Product> response = await container.PatchItemAsync<Product>( id: "e379aea5-63f5-4623-9a9b-4cd9b33b91d5", partitionKey: new PartitionKey("road-bikes"), patchOperations: new[] { PatchOperation.Replace("/price", 355.45) } ); Product updated = response.Resource;
合并多个补丁操作:
List<PatchOperation> operations = new () { PatchOperation.Add("/color", "silver"), PatchOperation.Remove("/used"), PatchOperation.Increment("/price", 50.00), PatchOperation.Add("/tags/-", "featured-bikes") }; ItemResponse<Product> response = await container.PatchItemAsync<Product>( id: "e379aea5-63f5-4623-9a9b-4cd9b33b91d5", partitionKey: new PartitionKey("road-bikes"), patchOperations: operations );
基于筛选器谓词使用条件补丁语法:
PatchItemRequestOptions options = new() { FilterPredicate = "FROM products p WHERE p.used = false" }; List<PatchOperation> operations = new () { PatchOperation.Replace($"/price", 100.00), }; ItemResponse<Product> response = await container.PatchItemAsync<Product>( id: "e379aea5-63f5-4623-9a9b-4cd9b33b91d5", partitionKey: new PartitionKey("road-bikes"), patchOperations: operations, requestOptions: options );
作为事务的一部分运行补丁操作:
TransactionalBatchPatchItemRequestOptions options = new() { FilterPredicate = "FROM products p WHERE p.used = false" }; List<PatchOperation> operations = new () { PatchOperation.Add($"/new", true), PatchOperation.Remove($"/used") }; TransactionalBatch batch = container.CreateTransactionalBatch( partitionKey: new PartitionKey("road-bikes") ); batch.PatchItem( id: "e379aea5-63f5-4623-9a9b-4cd9b33b91d5", patchOperations: operations, requestOptions: options ); batch.PatchItem( id: "892f609b-8885-44df-a9ed-cce6c0bd2b9e", patchOperations: operations, requestOptions: options ); TransactionalBatchResponse response = await batch.ExecuteAsync(); bool success = response.IsSuccessStatusCode;
支持服务器端编程
也可以使用存储过程、触发器和用户定义的函数 在服务器端执行 部分文档更新操作。
this.patchDocument = function (documentLink, patchSpec, options, callback) {
if (arguments.length < 2) {
throw new Error(ErrorCodes.BadRequest, sprintf(errorMessages.invalidFunctionCall, 'patchDocument', 2, arguments.length));
}
if (patchSpec === null || !(typeof patchSpec === "object" || Array.isArray(patchSpec))) {
throw new Error(ErrorCodes.BadRequest, errorMessages.patchSpecMustBeObjectOrArray);
}
var documentIdTuple = validateDocumentLink(documentLink, false);
var collectionRid = documentIdTuple.collId;
var documentResourceIdentifier = documentIdTuple.docId;
var isNameRouted = documentIdTuple.isNameRouted;
patchSpec = JSON.stringify(patchSpec);
var optionsCallbackTuple = validateOptionsAndCallback(options, callback);
options = optionsCallbackTuple.options;
callback = optionsCallbackTuple.callback;
var etag = options.etag || '';
var indexAction = options.indexAction || '';
return collectionObjRaw.patch(
collectionRid,
documentResourceIdentifier,
isNameRouted,
patchSpec,
etag,
indexAction,
function (err, response) {
if (callback) {
if (err) {
callback(err);
} else {
callback(undefined, JSON.parse(response.body), response.options);
}
} else {
if (err) {
throw err;
}
}
}
);
};
注意
在 GitHub 上的 .js DocDbWrapperScript 中查找 validateOptionsAndCallback
的定义。
修补操作的示例存储过程:
function patchDemo() {
var doc = {
"id": "exampleDoc",
"fields": {
"field1": "exampleString",
"field2": 20,
"field3": 40
}
};
var isAccepted = __.createDocument(__.getSelfLink(), doc, (err, doc) => {
if (err) {
throw err;
}
else {
getContext().getResponse().setBody("Example document successfully created.");
var patchSpec = [
{ "op": "add", "path": "/fields/field1", "value": "newExampleString" },
{ "op": "remove", "path": "/fields/field2" },
{ "op": "incr", "path": "/fields/field3", "value": 10 }
];
var isAccepted = __.patchDocument(doc._self, patchSpec, (err, doc) => {
if (err) {
throw err;
}
else {
getContext().getResponse().appendBody(" Example document successfully patched.");
}
});
if (!isAccepted) throw new Error("Patch wasn't accepted");
}
});
if (!isAccepted) throw new Error("Create wasn't accepted.");
}
故障排除
下面是使用此功能时可能会遇到的一些常见错误:
错误消息 | 说明 |
---|---|
补丁请求无效:请检查补丁规范的语法。 | 补丁操作语法无效。 有关详细信息,请参阅 部分文档更新规范。 |
无效的补丁请求:无法修补系统属性 SYSTEM_PROPERTY 。 |
系统生成的属性(例如 _id 、_ts 、_etag 、_rid )无法使用 补丁操作进行修改。 有关详细信息,请参阅 部分文档更新 FAQ。 |
补丁操作次数不能超过 10。 | 在单个补丁规范中最多可以添加 10 个补丁操作。 有关详细信息,请参阅 部分文档更新 FAQ。 |
对于操作(PATCH_OPERATION_INDEX ):要操作的索引(ARRAY_INDEX )超出数组界。 |
要修补的数组元素的索引超出边界。 |
对于操作 (PATCH_OPERATION_INDEX ):要替换的节点 (PATH ) 之前已在事务中删除。 |
你尝试修补的补丁并不存在。 |
对于操作 (PATCH_OPERATION_INDEX ):要删除的节点 (PATH ) 不存在。 注意:也可能之前已在事务中删除该内容。 |
你尝试修补的补丁并不存在。 |
对于操作 (PATCH_OPERATION_INDEX ):要替换的节点 (PATH ) 不存在。 |
你尝试修补的补丁并不存在。 |
对于操作 (PATCH_OPERATION_INDEX ):节点 (PATH ) 不是数字。 |
增量操作只能处理整数和浮点数。 有关详细信息,请参阅 受支持的操作。 |
对于操作(PATCH_OPERATION_INDEX ):“添加操作”只能创建现有节点(数组或对象)的子对象,且无法以递归方式创建路径,在 PATH 外找不到路径。 |
子路径可以添加到对象或数组节点类型。 此外,要创建第 n 个子级,应存在第 n-1 个子级。 |
对于操作 (PATCH_OPERATION_INDEX ):给定操作只能创建现有节点(数组或对象)的子对象,无法以递归方式创建路径,在 PATH 之外找不到路径。 |
子路径可以添加到对象或数组节点类型。 此外,要创建第 n 个子级,应存在第 n-1 个子级。 |