我编写了一个用于向DocumentDB集合中的所有文档添加Type属性的存储过程。遗憾的是,更新一个文档后存储过程失败。该集合包含大约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();
}
}}
根据返回的响应,我可以看到查询返回100个文档。 tryUpdate被调用两次,但不接受第二次调用replaceDocument。当有许多文件要更新时,为什么不接受?
答案 0 :(得分:1)
根据我对同一问题的回答MSDN
是的,对于每秒仅允许250RU的集合,每插入700RU +(估计)20RU将成为问题。查询是700RU,因为您正在执行NOT操作,这实际上是一次扫描,因为无法对其进行索引。
所以要尝试一些事情;
1)更改逻辑以排除NOT is_defined检查以及可能通过_ts DESC排序以获取最后更新的文档。这可能比做NOT检查便宜。然后你可以检查你已经获得的每个文档,如果它已经有一个Type属性,如果没有添加一个和ReplaceDocument
2)您还可以在执行此操作时尝试将集合扩展到S3,然后再将其缩放回S1。这将为您提供2500 RU。
3)即使使用S3,你仍然可能会遇到这种情况,它可能只发生在比第二个更多的文档之后。
所以,为了解决这个问题,我会在app中执行一个查询,只返回没有定义属性的记录的id,
SELECT VALUE c.id FROM c WHERE NOT is_defined(c.Type)
将这些ID粘贴到某种列表/数组中,然后从列表中获取()项目并将其作为数组传递给sproc。现在让sproc循环遍历传递的数组,通过id执行ReadDocument,更新并替换和增加计数器。
当isAccepted返回false时,将响应主体设置为计数器的值并返回到调用代码。现在调用代码可以跳过(计数器)。取(x)并再次调用sproc。
查看this sample以获取如何通过存储过程进行批量插入的示例。这显示了如何批处理记录,执行sproc,并在响应正文中isAccepted == false之前获取sproc到达该批处理的当前位置。