mongodb:原子地重命名两个集合?

时间:2012-11-06 02:07:53

标签: mongodb

我有两个现有的集合“A”和“B”。我需要将“B”重命名为“C”,并将“A”重命名为“B”,而不允许在此期间对B进行任何写入。重命名本身会激活全局锁定,但我需要防止在重命名之间发生写入。这可能吗?

这是我的代码:

db.B.renameCollection('C')
                           <-- prevent writes from occurring to B in between commands
db.A.renameCollection('B')

编辑:我正在使用mongodb 1.8.1版本,目前无法更改版本。

5 个答案:

答案 0 :(得分:4)

Mongodb本身无法处理这个问题,唯一可行的方法就是使用一些自定义代码。

如果这只会在你的应用程序中出现一次(我想重命名集合不是经常做的事情)你可以有一个更“积极”的方法,你在数据库中搜索一个标志'收集' db.B已重命名但db.A尚未'。如果所有写入都在将提交写入服务器之前检查了这一点,并且只是在设置了标志时返回,则可以保护应用程序在重命名db.B之后不写入db.A.

我认为这是'积极'的方法,因为它明显影响了性能(仍然,读取速度很快,你可能不会感觉到它)。

如果您的应用程序在单个Web服务器(而不是Web场)上运行,您可以在Web应用程序本身上使用同步机制,使用信号量等线程同步工具,甚至可以使用某些线程安全变量我上面建议的旗帜。 (取决于您使用的服务器端技术)

答案 1 :(得分:3)

你可以猜到:这是不可能的。没有事务支持,只有原子操作。

答案 2 :(得分:2)

我在TokuMX with multi-statement transactions上为Tokutek工作。

正如其他答案所说,MongoDB不能这样做(据我所知),但TokuMX可以。 TokuMX在非分片集群上具有多语句事务。要执行此操作,您可以执行以下操作:

  • db.beginTransaction()
  • db.B.renameCollection( 'C')
  • db.A.renameCollection( 'B')
  • db.commitTransaction()

答案 3 :(得分:2)

您可以创建一个名为&#34; renameCollection&#34;的函数。并锁上它:

db.runCommand({eval:renameCollection,args:["Collection1","Collection2"],nolock:false});

锁允许安全地执行此类操作并等待请求

答案 4 :(得分:1)

MongoDB没有事务性重命名的意义,事实上我不确定SQL在这种情况下是否也会这样做,但是你可以通过一些服务器端编程和锁集合来实现这一点。

从服务器端语言中,您可以在向锁定表写入行时触发命令,针对B的每个查询都将检查是否锁定,如果未找到则将写入,否则将会挽救。

这是一个简单的方法,但很可能有点单调乏味,特别是如果你有一个非常分段的代码库,它在服务器端代码和数据库之间没有标准化的查询层。

我还应该注意renameCollection不会对分片集合起作用,你很可能已经知道了,但我想我还是会说它。在分片收集的情况下,最好通过复制OP来“移动”集合。