你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

Azure Cosmos DB 部分文档更新入门

适用范围: NoSQL

本文提供的示例说明了如何将部分文档更新与 .NET、Java 和 Node SDK 结合使用。 它还描述了可能会遇到的常见错误。

本文链接到以下场景的代码示例:

  • 运行单个补丁操作
  • 合并多个补丁操作
  • 基于筛选器谓词使用条件补丁语法
  • 作为事务的一部分运行补丁操作

先决条件

从版本 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 个子级。

后续步骤