Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongodb: atomically rename two collections?

Tags:

mongodb

I have two existing collections "A" and "B". I need to rename "B" to "C", and rename "A" to "B", without permitting any writes to B during that time. The rename itself activates the global lock, but I need to prevent writes from occurring in between renames. Is this possible?

Here's my code:

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

Edit: I'm using mongodb version 1.8.1, and changing versions is not currently an option.

like image 790
Heinrich Schmetterling Avatar asked Nov 06 '12 02:11

Heinrich Schmetterling


4 Answers

Mongodb itself cannot handle this, the only way you could do this is with some custom code.

If this will only occur one time in your app ( I guess renaming collections is not something that is done often ) you could have a more 'aggressive' approach, where you search for a flag in your database that will mean 'collection db.B has been renamed but db.A not yet'. If all your writes check for this before submitting the write to the server and just return if the flag is set, it can protect the app from writing to db.A after db.B is renamed.

I consider this the 'aggressive' approach since it clearly affects performance ( still, reads are so fast, you probably won't feel it ).

If your app runs on a single web server (and not a web farm) you can have the synchronization mechanism on the web app itself, using thread synchronization tools like semaphores, etc or even some thread safe variable that will be used as the flag I suggested above. (depends on the server side technology you are using )

like image 119
VladT Avatar answered Nov 03 '22 11:11

VladT


You can create a function named "renameCollection" and put a lock on it :

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

The lock allows to do this kind of operations safely and make wait the requests

like image 4
歌永_ Avatar answered Nov 03 '22 11:11

歌永_


As you could guess: this is not possible. No transaction support, only atomic operations.

like image 3
Andreas Jung Avatar answered Nov 03 '22 12:11

Andreas Jung


MongoDB has no sense of transactional renames, in fact I am not sure if SQL does in this case either, however you could accomplish this with a bit of server-side programming and a lock collection.

From your server side language you can fire off the commands while writing a row to a lock table, each query against B will check for lock, if not found will write otherwise will bail out.

This is a simple method however most likely a bit tedious, especially if you have a very segmented code base that does not house a standardised query layer between the server-side code and the database.

I should also note that renameCollection will not work on sharded collections, you most likely already knew that but I thought I would just say it anyway. In the case of sharded collection it would be better to "move" the collection instead via copy OPs.

like image 1
Sammaye Avatar answered Nov 03 '22 10:11

Sammaye