9

PHP 的 Mongo 驱动程序缺少 renameCommand 函数。通过 admin 数据库可以参考。但是,如果您在该数据库上没有登录权限,似乎最新版本的 Mongo 驱动程序不允许您“使用”管理数据库。所以这种方法不再有效。我也读过这在分片环境中不起作用,尽管目前这对我来说不是一个问题。

人们似乎有的另一个建议是遍历“from”集合并插入“to”集合。使用适当的 WriteConcern(即发即弃),这可能会相当快。但这仍然意味着通过网络将每条记录拉入 PHP 进程,然后通过网络将其上传回数据库。

理想情况下,我想要一种在服务器端完成所有工作的方法。有点像 SQL 中的 INSERT INTO ... SELECT ...。这种方式速度快、网络高效且 PHP 负载低。

4

3 回答 3

3

我刚刚对此进行了测试,它按设计工作(http://docs.mongodb.org/manual/reference/command/renameCollection/):

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

这就是您重命名非分片集合的方式。MR 的一个问题是它会改变原始集合的输出形状。因此,它不太擅长复制集合。如果您的收藏被分片,您最好手动复制它。

作为补充说明,我升级到 1.4.2 (由于某种原因,它从 pecl 通道进入 phpinfo() 作为 1.4.3dev :S)并且它仍然有效。

于 2013-07-22T17:31:14.073 回答
0

更新

  • 删除了我的旧 map/reduce 方法,因为我发现(并且 Sammaye 指出)这会改变结构
  • 使我的 exec 版本成为次要版本,因为我发现了如何使用 renameCollection 来做到这一点。

我相信我已经找到了解决办法。似乎某些版本的 PHP 驱动程序将针对 admin 数据库进行身份验证,即使它不需要这样做。但是有一种解决方法,其中 authSource 连接参数用于更改此行为,因此它不会针对 admin 数据库进行身份验证,而是针对您选择的数据库进行身份验证。所以现在我的 renameCollection 函数只是 renameCollection 命令的一个包装器。

关键是连接的时候加上authSource。在下面的代码中,$_ENV['MONGO_URI'] 保存了我的连接字符串,default_database_name() 返回了我要对其进行身份验证的数据库的名称。

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

这是我使用 eval 的旧版本,尽管某些环境不允许您进行 eval,但它也应该可以工作(除非您有专用系统,否则MongoLab会为您提供残缺的设置)。但是,如果您在分片环境中运行,这似乎是一个合理的解决方案。

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();
}
于 2013-07-22T17:20:06.930 回答
-2

你可以用这个。“dropTarget”标志为真,然后删除现有数据库。

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

    $mongo->admin->command($query);
于 2013-12-17T16:33:12.310 回答