Можно ли в Cosmos DB создать односвязный список документов? - PullRequest
0 голосов
/ 17 ноября 2018

Одна проблема, которую я обычно решаю, - это сохранение неизменяемых версий документа, а не редактирование документа.При запросе документа получите самую последнюю версию.

Один из способов сделать это - использовать временные метки:

doc 0:

{
   id: "e69e0bea-77ea-4d97-bedf-d3cca27ae4b6",
   correlationId: "d00be916-10e3-415c-aaf6-9acb7c70cf4f",
   created: "11/17/2018 2:20:25 AM",
   value: "foo"
}

doc 1:

{
   id: "37ef6f99-bc87-45bb-87ae-a1b81070cc91",
   correlationId: "d00be916-10e3-415c-aaf6-9acb7c70cf4f",
   created: "11/17/2018 2:20:44 AM",
   value: "bar"
}

doc 2:

{
   id: "93fc913e-5ecc-4c59-a130-0e577ed4f2fb",
   correlationId: "d00be916-10e3-415c-aaf6-9acb7c70cf4f",
   created: "11/17/2018 2:21:51 AM",
   value: "baz"
}

Недостатком использования меток времени является необходимость заказа по метке времени (O(n*log(n))), чтобы получить N-ю самую последнюю версию.

Я хочу сделать это O(n), сохранив указатели на предыдущую версию, например

{
   id: "e69e0bea-77ea-4d97-bedf-d3cca27ae4b6",
   previousId: null,
   correlationId: "d00be916-10e3-415c-aaf6-9acb7c70cf4f",
   created: "11/17/2018 2:20:25 AM",
   value: "foo"
}

doc 1:

{
   id: "37ef6f99-bc87-45bb-87ae-a1b81070cc91",
   previousId: "e69e0bea-77ea-4d97-bedf-d3cca27ae4b6",
   correlationId: "d00be916-10e3-415c-aaf6-9acb7c70cf4f",
   created: "11/17/2018 2:20:44 AM",
   value: "bar"
}

doc 2:

{
   id: "93fc913e-5ecc-4c59-a130-0e577ed4f2fb",
   previousId: "37ef6f99-bc87-45bb-87ae-a1b81070cc91",
   correlationId: "d00be916-10e3-415c-aaf6-9acb7c70cf4f",
   created: "11/17/2018 2:21:51 AM",
   value: "baz"
}

, так что это связанный список, подобный

NULL <- doc0 <- doc1 <- doc2

Единственное, что мешает мне сделать это, - это то, что для создания новой версии мне понадобится некоторый механизм блокировки, например (в псевдокоде)

lock correlationId
   get latest
   new.previousId = latest.id
   insert new

но я не уверен, возможно ли это на уровне базы данных.

Ответы [ 2 ]

0 голосов
/ 17 ноября 2018

Нет концепции блокировки , но в вашем случае вы можете воспользоваться преимуществами уникальных ключевых ограничений:

  • Создать секционированную коллекцию с correlationId в качестве логическогоключ разделения
  • Добавить ограничение уникального ключа, ключ которого основан на previousId

На данный момент, для данного correlationId, если вы попытаетесь создать новую ссылкув списке, и каким-то другим образом, созданным непосредственно перед этим, вы столкнетесь с коллизией на previousId, и тогда вы сможете снова выполнить свою операцию, используя идентификатор только что созданного документа для previousId.

Примечание: - это ETag для каждого документа, что помогает с параллелизмом при обновлении документа, если вы решите использовать обновления в какой-то момент.

0 голосов
/ 17 ноября 2018

Рассматривали ли вы Cosmos DB Graph API.Связанный список - фактически очень простая форма графика.

То, что вы делаете, выглядит хорошо, но обновление идентификатора корреляции может привести к путанице.С API Graph такой проблемы не будет.

Обновление ответа после первого комментария:

Это то, что мы можем сделать, используя SQL API.

Цепочка может бытьсмоделировано как:

NULL <- Doc1 <- Doc2 <- Doc3 <- Head.

Голова имеет тот же correlationId, что и документы других версий.Кроме того, correlationId должен быть ключом раздела коллекции, чтобы все версии одних и тех же документов помещались в один и тот же физический раздел.

Теперь мы можем использовать хранимую процедуру для обновления версии документа.,Обратите внимание, что хранимые процедуры являются транзакционными в рамках ключа раздела (причина, по которой мы хотели, чтобы correlationId был ключом раздела).

Ниже приведен псевдокод хранимой процедуры.

Add New version: 
    Read the Head(H) Document 
    save the _etag of the Head Document 
    Follow H to read the current most recent version (CMRV)
    Add a document for the new most recent version (NMRV)
    Point H to NRMV and NMRV to CMRV
    Update H with some dummy information (say number of version) using the _etag saved before

Вся эта часть атомная.Если другой параллельный поток успешно обновил H, текущий сохраненный процесс завершится с ошибкой «Предварительное условие» (из-за несоответствия _etag), и весь сохраненный процесс будет откатан.

...