2016-03-15 80 views
0

我已经编写了一个存储过程,用于为DocumentDB集合中的所有文档添加一个Type属性。不幸的是,更新一个文档后存储过程失败。该集合包含大约5000个文档。DocumentDB更新多个文档失败

这里是存储过程:

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

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

+0

我花了大约20分钟的时间来看这个,我没有看到任何明显的。我看到的唯一小事不会导致你的问题。即使isAccepted为false,也可以调用tryUpdate(),这意味着您可能会在DocumentDB告诉您它不再接受操作之后尝试调用replaceDocument()。我唯一可以尝试的方法是将文档放在顶层函数作用域中,然后在查询中将您的回调改为“结果”而不是“文档”,并在错误发生后立即添加“文档=结果”检查。 –

+0

哦,它看起来像你的代码将永远不会看到调用tryQueryAndUpdate一个延续块,但这意味着你不能得到第二页,它不会导致你的第二个replaceDocuments()调用失败。我会更多的面条,也许尝试它自己的生活。 –

+0

哦,如果您将文档移动到顶层作用域中,请记住不要将文档传递到tryUpdate。 –

回答

1

按我的回答对同一问题MSDN

是,700RUs +每个刀片(估计)20RUs,对集合,只允许每秒250RUs将是一个问题。该查询是700RU,因为您正在执行NOT操作,该操作实际上是扫描,因为无法对其进行索引。

所以有些事情要尝试;

1)更改逻辑以排除NOT is_defined检查,也可能排除Order by _ts DESC以获取最后更新的文档。这可能比做NOT检查便宜。然后你可以检查你得到的每个文档,如果它有一个Type属性,如果没有添加一个,并且替换文档

2)你也可以尝试缩放集合到S3,而你正在做这个操作,然后缩放它再次回到S1。这会给你2500 RU。

3)即使使用S3,您仍然可能会遇到这种情况,它可能发生在比第二个更多的文档之后。

所以,要解决我会在应用程序执行的查询返回的是没有足够的财产定义的记录只是ID,

选择值c.id由C WHERE NOT is_defined(c.Type )

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

当isAccepted返回false时,将响应主体设置为计数器的值并返回到调用代码。现在调用代码可以跳过(计数器)。取(x)并再次调用存储器。

查看this sample了解如何通过存储过程执行批量插入的示例。这显示了如何批量记录,执行一个存储过程,并获取当前位置,该存储过程在响应正文中isAccepted == false之前获取到该批次中。