2016-03-15 3 views
0

Я написал хранимую процедуру af для добавления свойства Type ко всем документам в коллекции DocumentDB. К сожалению, хранимая процедура завершилась неудачей после обновления только одного документа. Коллекция содержит около 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 минут на это, и я не вижу ничего очевидного. Единственная незначительная вещь, которую я видел, не вызовет вашей проблемы. Вы вызываете tryUpdate(), даже если isAccepted является false, что означает, что вы можете попытаться вызвать replaceDocument() после того, как DocumentDB сообщит вам, что он больше не принимает операции. Единственное, что я мог попробовать, это поместить документы в область функций верхнего уровня, а затем изменить обратный вызов в запросе, чтобы сказать «результаты» вместо «документы» и добавить «документы = результаты» сразу после вашей ошибки проверить. –

+0

Ой, похоже, ваш код никогда не увидит блок, который вызывает tryQueryAndUpdate с продолжением, но это будет означать, что вы не можете получить вторую страницу, это не приведет к сбою второго вызова replaceDocuments().Я буду лапшу на нем еще и, возможно, попробую жить сам. –

+0

Ох, если вы переместите документы в область верхнего уровня, тогда не забудьте не передавать документы в файл tryUpdate. –

ответ

1

В соответствии с моим ответом на тот же вопрос MSDN

Да, 700RUs + (оценка) 20RUs за вставку, на коллекции, которая позволяет только 250RUs в секунду будет проблемой. Запрос - это 700RU, потому что вы выполняете операцию NOT, что эффективно проверяет, потому что это невозможно проиндексировать.

Так что некоторые вещи, чтобы попробовать;

1) Измените логику, чтобы исключить проверку NOT is_defined и, возможно, Order By _ts DESC, чтобы получить документы, которые были обновлены в последнюю очередь. Это может быть дешевле, чем проверка NOT. Затем вы можете проверить каждый документ, если у него уже есть свойство Type, если оно не добавлено, и ReplaceDocument

2) Вы также можете попробовать масштабировать коллекцию до S3 во время выполнения этой операции, а затем масштабировать ее снова вернитесь к S1. Это даст вам 2500 RU для игры.

3) Даже используя S3, вы все равно можете столкнуться с этим, это может произойти после нескольких документов, чем второй.

Таким образом, чтобы исправить, я бы выполнить запрос в приложение, чтобы возвращать только идентификатор записи, которые не имеют свойство определено,

ВЫБОР VALUE c.id ОТ с WHERE NOT is_defined (Тип Ç)

Вставьте эти идентификаторы в список/массив какого-либо типа, а затем .Take() элементы из списка и перейдите в sproc как массив. Теперь получим цикл sproc через переданный массив, который выполняет ReadDocument по идентификатору, обновляет и заменяет и увеличивает счетчик.

Когда isAccepted возвращает false, установите тело ответа на значение счетчика и верните код вызова. Теперь вызывающий код может затем пропустить (счетчик) .Take (x) и снова вызвать sproc.

Посмотрите на this sample на пример того, как делать объемную вставку через хранимую процедуру. Это показывает, как выполнять пакетные записи, выполнять sproc и получать текущую позицию, которую sproc получил в этой партии, прежде чем isAccepted == false из тела ответа.