MongoDB:如何原子重命名两个集合?

6
我有两个现有的集合"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,当前不能更改版本。


好的,你可以在重命名期间防止写入,但这需要使用私有端口重新启动服务器 :) - Sergio Tulentsev
5个回答

4
您可以创建一个名为 "renameCollection" 的函数,并对其进行锁定:
db.runCommand({eval:renameCollection,args:["Collection1","Collection2"],nolock:false});

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

4
MongoDB本身无法处理此事,您唯一能够做的是使用一些自定义代码。如果这仅在您的应用程序中发生一次(我猜重命名集合不是经常进行的操作),您可以采取更为“激进”的方法,在数据库中搜索一个标志,表示“集合db.B已重命名,但db.A尚未重命名”。如果所有写操作在提交到服务器之前检查该标志,并且当标志被设置时只返回,则可以保护应用程序在将db.B重命名后写入db.A。我认为这是“激进”方法,因为它明显会影响性能(不过,由于读取速度很快,您可能不会感觉到它)。如果您的应用程序在单个Web服务器上运行(而不是Web农场),则可以在Web应用程序本身上使用同步机制,例如信号量等线程同步工具,甚至可以使用某些线程安全变量作为上述建议的标志(具体取决于您所使用的服务器端技术)。

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

1

我在Tokutek工作,负责TokuMX多语句事务

正如其他答案所说,据我所知,MongoDB无法实现此功能,但TokuMX可以。 TokuMX在非分片集群上具有多语句事务功能。 要执行此操作,您可以执行以下操作:

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

1

MongoDB没有事务重命名的概念,实际上我不确定SQL在这种情况下是否有,但是您可以通过一些服务器端编程和锁定集合来实现此操作。

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

这是一种简单的方法,但很可能有点繁琐,特别是如果您的代码库非常分散,不包含服务器端代码和数据库之间的标准化查询层。

我还应该注意到,renameCollection无法在分片集合上工作,您很可能已经知道了,但我还是想说一下。在分片集合的情况下,最好通过复制操作“移动”集合。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接