我通常要解决的一个问题是保留文档的不变版本而不是编辑文档。当要求提供文档时,请获取最新版本。
一种方法是使用时间戳:
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
但是我不确定在数据库级别是否可行。
答案 0 :(得分:0)
没有锁定的概念,但是在您的情况下,您可以利用唯一的键约束:
correlationId
作为逻辑分区键创建一个分区集合previousId
这时,对于给定的correlationId
,如果尝试在列表中创建一个新链接,而又以某种方式在之前创建了另一个链接,则会在previousId
上遇到冲突,然后您就可以使用刚刚创建的previousId
的文档ID来重新执行操作。
注意:每个文档都有一个 ETag,如果您决定在某个时候使用更新,则在更新文档时该功能有助于并发。
答案 1 :(得分:-1)
您是否考虑过Cosmos DB Graph API。链接列表实际上是图的一种非常基本的形式。
您正在做的事情看起来不错,但是更新相关ID可能会很混乱。有了图谱API,就不会出现问题了。
在第一条评论之后更新答案:
该链可以建模为:
NULL <- Doc1 <- Doc2 <- Doc3 <- Head.
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,则当前存储的proc将失败,并显示“ Precondition”失败错误(由于_etag不匹配),并且整个存储的proc将回滚。