如何在SSH可访问的跨主机Mongo实例间复制单条集合记录
我来帮你搞定这个问题!因为两个Mongo实例都部署在需要SSH访问的主机上,直接用mongodump/mongorestore确实没法直接连接,但我们可以通过SSH端口转发来打通本地和远程Mongo的连接,或者直接用mongosh结合隧道完成单条记录的复制,下面是两种实用的实现方案:
方案一:SSH端口转发 + mongodump/mongorestore(适合需要保留备份的场景)
这种方法先把目标记录导出到本地,再导入到目标实例,步骤清晰:
建立到dev实例的SSH端口转发
把远程dev主机的Mongo端口(默认27017)映射到本地的27018端口(可以换其他未被占用的端口):ssh -L 27018:localhost:27017 dev-ssh-user@dev-host-ip说明:
dev-ssh-user是dev主机的SSH登录用户名,dev-host-ip是dev主机的IP或域名;如果SSH需要密钥认证,加上-i /path/to/your/private-key.pem参数。导出dev实例中的单条记录
用mongodump指定查询条件,只导出目标记录:mongodump --port 27018 --db your-db-name --collection your-collection-name --query '{"_id": ObjectId("your-target-document-id")}' --out ./temp-mongo-dump说明:
your-db-name是数据库名,your-collection-name是集合名,your-target-document-id是你要复制的记录的_id值;导出的文件会存到本地temp-mongo-dump目录下。建立到stage实例的SSH端口转发
同理,把stage主机的Mongo端口映射到本地27019端口:ssh -L 27019:localhost:27017 stage-ssh-user@stage-host-ip将导出的记录导入到stage实例
用mongorestore把本地备份的记录导入到stage的对应集合:mongorestore --port 27019 --db your-db-name --collection your-collection-name ./temp-mongo-dump/your-db-name/your-collection-name.bson
方案二:mongosh结合SSH隧道直接复制(更高效,无中间文件)
这种方法直接在Mongo Shell中完成记录的读取和插入,不用生成备份文件:
建立到dev实例的SSH端口转发
同方案一的第一步,先打通本地到dev的Mongo连接:ssh -L 27018:localhost:27017 dev-ssh-user@dev-host-ip在mongosh中获取目标记录
打开新的终端,连接到本地转发的dev端口:mongosh --port 27018进入Mongo Shell后,执行命令获取目标记录并输出:
// 切换到目标数据库和集合,查询单条记录 const targetDoc = db.getSiblingDB('your-db-name').your-collection-name.findOne({"_id": ObjectId("your-target-document-id")}); // 打印记录的JSON格式,方便复制 printjson(targetDoc);把输出的JSON内容复制下来。
建立到stage实例的SSH端口转发
同方案一的第三步,打通本地到stage的连接:ssh -L 27019:localhost:27017 stage-ssh-user@stage-host-ip在mongosh中插入记录到stage
打开新终端连接到stage的转发端口:mongosh --port 27019执行插入命令,把刚才复制的JSON内容填进去:
db.getSiblingDB('your-db-name').your-collection-name.insertOne(/* 粘贴刚才复制的targetDoc的JSON内容 */);
注意事项
- 如果Mongo实例开启了用户认证,在使用
mongodump/mongorestore/mongosh时需要加上--username your-mongo-user --password your-mongo-password参数(或者在Shell中用db.auth()认证)。 - 本地端口如果被占用,更换为其他未被使用的端口即可(比如把27018换成30000)。
- 保持SSH端口转发的终端窗口处于打开状态,关闭后转发会失效。
内容的提问来源于stack exchange,提问作者Ramavi

