Share via


Azure Cosmos DB の部分的なドキュメント更新の概要

適用対象: NoSQL

この記事では、.NET、Java、Node の各 SDK で部分的なドキュメント更新を使用する方法を示す例を紹介します。 また、発生する可能性がある一般的なエラーについても説明します。

この記事は、次のシナリオのコード サンプルにリンクしています。

  • 1 つのパッチ操作の実行
  • 複数のパッチ操作の組み合わせ
  • フィルター述語に基づく条件付きパッチ構文の使用
  • トランザクションの一部としてのパッチ操作の実行

前提条件

Azure Cosmos DB .NET v3 SDK の部分的なドキュメント更新 (Patch API) のサポートは、バージョン 3.23.0 以降で利用できます。 NuGet ギャラリーからダウンロードできます。

注意

部分的なドキュメント更新の完全なサンプルは、GitHub の .NET v3 サンプル リポジトリにあります。

  • 1 つのパッチ操作の実行:

    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;
                }
            }
        }
    );
}; 

注意

validateOptionsAndCallback の定義は、GitHub の .js DocDbWrapperScript にあります。

パッチ操作のサンプル ストアド プロシージャ:

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.");
}

トラブルシューティング

この機能の使用中に発生する可能性のある一般的なエラーを次に示します。

エラー メッセージ 説明
無効なパッチ要求: パッチの仕様の構文を確認してください。 パッチ操作の構文が無効です。 詳細については、部分的なドキュメント更新の仕様に関する記事を参照してください。
Invalid patch request: Cannot patch system property SYSTEM_PROPERTY (無効なパッチ要求: システム プロパティ SYSTEM_PROPERTY にはパッチを適用できません) _id_ts_etag_rid などのシステム生成プロパティは、パッチ操作を使用して変更できません。 詳細については、部分的なドキュメント更新の FAQ に関する記事を参照してください。
パッチ適用の操作数が 10 件を超えることはできません。 1 つのパッチの仕様に追加できるパッチ操作は 10 個までに制限されています。 詳細については、部分的なドキュメント更新の FAQ に関する記事を参照してください。
Operation(PATCH_OPERATION_INDEX) の場合: 操作する Index(ARRAY_INDEX) が配列の範囲外です 修正する配列要素のインデックスが範囲外です。
For Operation(PATCH_OPERATION_INDEX): Node(PATH) to be replaced has been removed earlier in the transaction. (Operation(PATCH_OPERATION_INDEX) の場合: 置き換える Node(PATH) がトランザクションで既に削除されています) パッチを適用しようとしているパスが存在しません。
For Operation(PATCH_OPERATION_INDEX): Node(PATH) to be removed is absent. (Operation(PATCH_OPERATION_INDEX) の場合: 削除する Node(PATH) が存在しません) 注: トランザクションで既に削除された可能性もあります。  パッチを適用しようとしているパスが存在しません。
For Operation(PATCH_OPERATION_INDEX): Node(PATH) to be replaced is absent. (Operation(PATCH_OPERATION_INDEX) の場合: 置き換える Node(PATH) が存在しません) パッチを適用しようとしているパスが存在しません。
For Operation(PATCH_OPERATION_INDEX): Node(PATH) is not a number. (Operation(PATCH_OPERATION_INDEX) の場合: Node(PATH) が数字ではありません) インクリメント操作は、整数と浮動でのみ機能します。 詳細については、「サポートされている操作」を参照してください。
Operation(PATCH_OPERATION_INDEX) の場合: 追加操作では、既存のノード (配列またはオブジェクト) の子オブジェクトのみを作成できます。また、パスを再帰的に作成することはできません。PATH 以降にパスがありません: PATH 子パスは、オブジェクトまたは配列ノード型に追加できます。 また、n 番目の子を作成するには、n-1 番目の子が存在している必要があります。
For Operation(PATCH_OPERATION_INDEX): Given Operation can only create a child object of an existing node(array or object) and cannot create path recursively, no path found beyond: PATH. (Operation(PATCH_OPERATION_INDEX) の場合: 指定の操作では、既存のノード (配列またはオブジェクト) の子オブジェクトのみを作成できます。また、パスを再帰的に作成することはできません。PATH 以降にパスがありません) 子パスは、オブジェクトまたは配列ノード型に追加できます。 また、n 番目の子を作成するには、n-1 番目の子が存在している必要があります。

次のステップ