DocumentDB 更新多个文档失败

DocumentDB updating multiple documents fails

我编写了一个存储过程,用于将类型 属性 添加到 DocumentDB 集合中的所有文档。不幸的是,存储过程在仅更新一个文档后就失败了。该集合包含大约 5000 份文件。

存储过程如下:

function updateSproc() {
var collection = getContext().getCollection();
var collectionLink = collection.getSelfLink();
var response = getContext().getResponse();
var responseBody = {
    updated: 0,
    continuation: true,
    error: "",
    log: ""
};

// Validate input.
tryQueryAndUpdate();

// Recursively queries for a document by id w/ support for continuation tokens.
// Calls tryUpdate(document) as soon as the query returns a document.
function tryQueryAndUpdate(continuation) {
    var query = { query: "SELECT * FROM root c WHERE NOT is_defined(c.Type)", parameters: []};
    var requestOptions = { continuation: continuation};

    var isAccepted = collection.queryDocuments(collectionLink, query, requestOptions, function(err, documents, responseOptions) {
        if (err) {
    responseBody.error = err;
    throw err;
        }

        if (documents.length > 0) {
            // If documents are found, update them.
            responseBody.log += "Found documents: " + documents.length;
            tryUpdate(documents);
        } else if (responseOptions.continuation) {
            responseBody.log += "Continue query";
            tryQueryAndUpdate(responseOptions.continuation);
        } else {
            responseBody.log += "No more documents";
            responseBody.continuation = false;
            response.setBody(responseBody);
        }

    });

    // If we hit execution bounds - throw an exception.
    if (!isAccepted) {
        responseBody.log += "Query not accepted";
        response.setBody(responseBody);
    }
}

// Updates the supplied document according to the update object passed in to the sproc.
function tryUpdate(documents)
{
    if (documents.length > 0) {
        responseBody.log += "Updating documents " + documents.length;

        var document = documents[0];

        // DocumentDB supports optimistic concurrency control via HTTP ETag.
        var requestOptions = { etag: document._etag};

        document.Type="Type value";

        // Update the document.
        var isAccepted = collection.replaceDocument(document._self, document, requestOptions, function(err, updatedDocument, responseOptions) {
           if (err) {
              responseBody.error = err;
              throw err;
           }

           responseBody.updated++;
           documents.shift();
           tryUpdate(documents);
        });

        // If we hit execution bounds - throw an exception.
        if (!isAccepted) {
            responseBody.log += "Update not accepted";
            response.setBody(responseBody);
        }
    } else {
        tryQueryAndUpdate();
    }
}}

根据返回的响应,我可以看到查询 returns 100 个文档。 tryUpdate 被调用两次,但不接受对 replaceDocument 的第二次调用。为什么要更新的文档很多,还是不接受?

根据我对同一问题的回答MSDN

是的,每个插入 700RUs +(估计)20RUs,在每秒只允许 250RUs 的集合上将是一个问题。查询是 700RU,因为您正在执行 NOT 操作,这实际上是一次扫描,因为它无法被索引。

所以有些事情要尝试;

1) 更改逻辑以排除 NOT is_defined 检查并可能按 _ts DESC 排序以获取最后更新的文档。这可能比做 NOT 检查便宜。然后你可以检查你得到的每个文档是否已经有 Type 属性,如果没有则添加一个和 ReplaceDocument

2) 您也可以尝试在执行此操作时将集合扩展到 S3,然后再次将其缩小到 S1。这会给你 2500 RUs 玩。

3) 即使使用 S3,您可能仍然 运行 参与其中,它可能只是发生在比第二个文档更多的文档之后。

所以,为了解决这个问题,我会在应用程序中执行查询 return 只是没有定义 属性 的记录的 ID,

SELECT 值 c.id 来自 c 而不是 is_defined(c.Type)

将这些 id 粘贴到某种列表/数组中,然后从列表中获取 () 项目并将其作为数组传递给 sproc。现在让 sproc 循环通过传递的数组,通过 id 执行 ReadDocument,更新和替换以及递增计数器。

当 isAccepted return 为 false 时,将响应主体设置为计数器的值,并将 return 设置为调用代码。现在调用代码可以 Skip(counter).Take(x) 并再次调用存储过程。

查看 this sample 中的示例,了解如何通过存储过程进行批量插入。这显示了如何批处理记录、执行存储过程,以及如何从响应正文中获取存储过程在 isAccepted == false 之前在该批处理中到达的当前位置。