Eric Anderson
Eric Anderson

Reputation: 3792

Renaming a Mongo Collection in PHP

PHP's Mongo driver lacks a renameCommand function. There is reference to do this through the admin database. But it seems more recent versions of the Mongo driver don't let you just "use" the admin database if do don't have login privileges on that database. So this method no longer works. I've also read this doesn't work in sharded environments although this isn't a concern for me currently.

The other suggestion people seem to have is to iterate through the "from" collection and insert into the "to" collection. With the proper WriteConcern (fire and forget) this could be fairly fast. But it still means pulling down each record over the network into the PHP process and then uploading it back over the network back into the database.

I ideally want a way to do it all server-side. Sort of like an INSERT INTO ... SELECT ... in SQL. This way it is fast, network efficient and a low load on PHP.

Upvotes: 9

Views: 3092

Answers (3)

muktesh patel
muktesh patel

Reputation: 41

you can use this. "dropTarget" flag is true then delete exist database.

 $mongo = new MongoClient('_MONGODB_HOST_URL_');
    $query = array("renameCollection" => "Database.OldName", "to" => "Database.NewName", "dropTarget" => "true");

    $mongo->admin->command($query);

Upvotes: -2

Eric Anderson
Eric Anderson

Reputation: 3792

Updates:

  • Removed my old map/reduce method since I found out (and Sammaye pointed out) that this changes the structure
  • Made my exec version secondary since I found out how to do it with renameCollection.

I believe I have found a solution. It appears some versions of the PHP driver will auth against the admin database even though it doesn't need to. But there is a workaround where the authSource connection param is used to change this behavior so it doesn't auth against the admin database but instead the database of your choice. So now my renameCollection function is just a wrapper around the renameCollection command again.

The key is to add authSource when connecting. In the below code $_ENV['MONGO_URI'] holds my connection string and default_database_name() returns the name of the database I want to auth against.

$class = 'MongoClient'; 
if( !class_exists($class) ) $class = 'Mongo'; 
$db_server = new $class($_ENV['MONGO_URI'].'?authSource='.default_database_name());

Here is my older version that used eval which should also work although some environments don't allow you to eval (MongoLab gives you a crippled setup unless you have a dedicated system). But if you are running in a sharded environment this seems like a reasonable solution.

function renameCollection($old_name, $new_name) {
  db()->$new_name->drop();
  $copy = "function() {db.$old_name.find().forEach(function(d) {db.$new_name.insert(d)})}";
  db()->execute($copy);
  db()->$old_name->drop();
}

Upvotes: 0

Sammaye
Sammaye

Reputation: 43884

I have just tested this, it works as designed ( http://docs.mongodb.org/manual/reference/command/renameCollection/ ):

$mongo->admin->command(array('renameCollection'=>'ns.user','to'=>'ns.e'));

That is how you rename an unsharded collection. One problem with MR is that it will change the shape of the output from the original collection. As such it is not very good at copying a collection. You would be better off copying it manually if your collection is sharded.

As an added note I upgraded to 1.4.2 (which for some reason comes out from the pecl channel into phpinfo() as 1.4.3dev :S) and it still works.

Upvotes: 3

Related Questions