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之前獲取到該批次中。