0

我在 mongodb 中有一个分片的文档集合,并且有几个应用程序服务器在访问它。

每个应用程序都会贡献新文档,最终还需要删除一些文档。

删除哪些文档并不重要,但重要的是它删除(声明)一个确切的数字,并且没有其他应用程序正在删除(声明)相同的文档。

我的想法是:

unique = makeUniqueValue()
docs = []

for (i = 0;i < 10;i++) {
    r = findAndModify( claim: false, $set: { claim: unique });
    if (r.value) docs.push(r);
}

if (docs.length < 10)
    "release all docs by updating (claim: false) and try again in some time"

此解决方案的一个潜在问题是,如果应用程序太多(而文档很少),他们只会继续声明一些文档并再次发布它们。

这个问题的众所周知且经过充分测试的解决方案是什么?

“update”和“findAndModify”是否保证更新后的文档与更新前的查询匹配?

或者另一个应用程序是否可以在匹配和更新之间“窃取”它,因此两个应用程序都认为他们已经声明了该文档?

4

1 回答 1

1

在该文档上运行更新后,它将确保查询与文档匹配并且它是最新版本。

没有其他程序应该能够在每个文档的基础上进行窃取。

进一步解释一下,因为我意识到这个答案有点简单:MongoDB 在数据库级别上有一个写入器贪婪的读/写锁。

这意味着findAndModify当写入操作被赋予运行能力时将无法找到某些东西。因此,例如,它无法找到将要更新的文档,如另一个线程/应用程序中声称的那样。

因此,此代码立即将文档声明隔离到一个应用程序,因为另一个应用程序的循环的每次迭代都会导致未声明文档,并且永远不会在 MongoDB 服务器上出现中间/部分状态。

实际更新时并不重要,因为您知道这些文档是您需要更新的文档,但是,诸如$setetc 之类的操作符在单个文档上按顺序运行,因为此类更新操作本身也不能获取部分文档状态,它们要么采用claim false要么没有什么。更新还将直接从数据文件中选择行,而不是从写出的静态结果集中。

如果您要使用该_id或其他静态数据进行更新,那么情况会有所不同。

于 2014-02-01T16:32:03.247 回答