Поделиться через


Начало работы с частичным обновлением документов в Azure Cosmos DB

ОБЛАСТЬ ПРИМЕНЕНИЯ: NoSQL

В этой статье приведены примеры использования частичного обновления документов с пакетами SDK для .NET, Java и Node. В нем также описываются распространенные ошибки, которые могут возникнуть.

В этой статье приводятся ссылки на примеры кода для следующих сценариев:

  • Выполнение одной операции исправления
  • Объединение нескольких операций исправления
  • Использование синтаксиса условного исправления на основе предиката фильтра
  • Выполнение операции исправления в рамках транзакции

Необходимые компоненты

Поддержка частичного обновления документов (API исправлений) в пакете SDK для .NET для .NET для Azure Cosmos DB версии 3 доступна начиная с версии 3.23.0. Его можно скачать из коллекции NuGet.

Примечание.

Найдите полный пример частичного обновления документов в репозитории примеров .NET версии 3 на GitHub.

  • Выполните одну операцию исправления:

    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 в .js DocDbWrapperScript на сайте GitHub.

Пример хранимой процедуры для операции исправления:

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

Устранение неполадок

Ниже приведены некоторые распространенные ошибки, которые могут возникнуть при использовании этой функции:

Сообщение об ошибке Description
Недопустимый запрос на исправление: проверьте синтаксис спецификации исправлений. Недопустимый синтаксис операции исправления. Дополнительные сведения см . в спецификации частичного обновления документов.
Неверный запрос исправления: не удается исправить системное свойство SYSTEM_PROPERTY. Системные свойства, такие как _id, _ts_etagне _rid изменяются с помощью операции исправления. Дополнительные сведения см. в часто задаваемых вопросы о частичном обновлении документов.
Количество операций исправления не может превышать 10. В отдельной спецификации исправления можно добавить не более 10 операций исправления. Дополнительные сведения см. в часто задаваемых вопросы о частичном обновлении документов.
Для operation(): Index(PATCH_OPERATION_INDEXARRAY_INDEX) для работы находится вне границ массива. Индекс элемента массива, который требуется исправить, выходит за рамки.
Для операция(PATCH_OPERATION_INDEX)): заменяемый узел(PATH) был удален ранее при выполнении транзакции. Путь, по которому вы пытаетесь установить исправление, не существует.
Для операция(PATCH_OPERATION_INDEX): отсутствует удаляемый узел(PATH). Примечание. Возможно, она также была удалена ранее в транзакции.  Путь, по которому вы пытаетесь установить исправление, не существует.
Для операция(PATCH_OPERATION_INDEX): отсутствует заменяемый узел(PATH). Путь, по которому вы пытаетесь установить исправление, не существует.
Для операции PATCH_OPERATION_INDEX: узел PATH не является числом. Операция приращения работает только для целых чисел и чисел с плавающей точкой. Дополнительные сведения см. в статье "Поддерживаемые операции".
Для Operation(PATCH_OPERATION_INDEX): Добавление операции может создавать только дочерний объект существующего узла (массива или объекта) и не может создавать путь рекурсивно, ни путь не найден за пределами: PATH Пути дочерних элементов можно добавить к типу узла объекта или массива. Кроме того, чтобы создать nдочерний элемент, n-1должен присутствовать его дочерний элемент.
Для операции PATCH_OPERATION_INDEX: указанная операция может только создать дочерний объект существующего узла (массива или объекта) и не может создать путь рекурсивно. Не найден путь после PATH. Пути дочерних элементов можно добавить к типу узла объекта или массива. Кроме того, чтобы создать nдочерний элемент, n-1должен присутствовать его дочерний элемент.

Следующие шаги