我正在处理页面层次结构(mongodb文档):
{
_id: 012,
content: "lorem ipsum whatever...",
subpages: [123,234,345,456], // page ids
}
页面结构实际上是高度动态的,因此许多读取会同时发生许多更新。但是,每次更改(例如将子页面移动到另一个页面)都需要至少2次更新操作:
// move 123 into page 234
db.pages.update({"_id":012}, {$pull:{"subpages":123}});
db.pages.update({"_id":234}, {$push:{"subpages":123}});
// delete page 345
db.pages.update({"_id":012}, {$pull:{"subpages":345}});
db.pages.remove({"_id":345});
有没有办法执行(或设计模型以启用执行)操作,例如移动页面或原子地删除页面(以防止层次结构的状态变坏)?
备注
我现在正在看的一种可能性是通过向每个页面添加“lockedBy”字段来手动锁定文档,该字段将包含事务ID。但我不喜欢连续轮询的想法,如果我想要阻止第二次锁定操作,直到第一次锁定操作完成(参见https://jira.mongodb.org/browse/SERVER-2244)。此外,由于锁定由应用程序管理,如果应用程序(或其中一个实例)在锁定操作期间因任何原因而关闭,则需要以某种方式解锁文档,而不会影响其他事务。
我也看过http://www.mongodb.org/display/DOCS/Trees+in+MongoDB,似乎没有一个例子(单个文档除外)解决了这个问题。但是,我想避免将整个层次结构放在一个文档中,因为16MB的文档大小限制以及移动页面的难度(基本上我需要为每次更改都插入整个文档)。
更新
我们希望为一个页面支持多达10000个子页面。页面的ID长度至少为6个字符。考虑到这一点,我们从mySQL迁移,因为我们需要跟踪子页面的顺序。由于mySQL没有数组结构,唯一的方法是使用位置列。当页面频繁移动时,计算平均位置并在位置值变得太长时重新索引是很昂贵的。此外,如果我们想将逗号分隔的id列表放入列中,我们必须使用TEXT列(从磁盘读取)而不是VARCHAR(其限制为65536个字符)以支持10000子 - 页。
答案 0 :(得分:2)
没有交易。有原子操作,但它们一次只能在一个文档上运行。我要说,您可靠更新的唯一选择是将整个层次结构放在一个文档中。我不会太担心超过文件限制:16MB是很多整数。
我想,这是一个“常规”关系事务数据库更有用的例子。