ChatGPT解决这个技术问题 Extra ChatGPT

如何在 MongoDB 中将集合从一个数据库复制到另一个数据库

有没有一种简单的方法可以做到这一点?

早在 2012 年,公认的答案可以说是最好的方法,但现在 db.cloneCollection() 通常是更好的解决方案。这里有几个最近的答案涉及到这个,所以如果你从谷歌来到这里(就像我一样)看看所有的答案!
请务必阅读其他答案,以确保它符合您的需求,而不仅仅是@kelvin 在他/她的情况下
@Naman 复制收集的用例是什么,我的意思是您需要任何命令还是可以手动处理?对于手动过程,只需安装 studio3T 连接两个数据库并右键单击要复制的集合,单击选项“复制集合”,然后转到第二个数据库,右键单击“集合”目录并单击选项“粘贴集合”。
@turivishal 这绝对是一种方式,但是命令行工具更加可靠,并且可以立即支持随升级发布的功能。顺便说一句,我已经提高了赏金来奖励现有的答案。 :)

N
Naman

最好的方法是先执行 mongodump,然后执行 mongorestore。您可以通过以下方式选择集合:

mongodump -d some_database -c some_collection

[可选地,压缩转储 (zip some_database.zip some_database/* -r) 并在别处scp ]

然后恢复它:

mongorestore -d some_other_db -c some_or_other_collection dump/some_collection.bson

some_or_other_collection 中的现有数据将被保留。这样,您就可以将集合从一个数据库“附加”到另一个数据库。

在版本 2.4.3 之前,您还需要在复制数据后重新添加索引。从 2.4.3 开始,此过程是自动的,您可以使用 --noIndexRestore 禁用它。


如果您有受密码保护的 mongo 实例,那么 mongodump 似乎不起作用(而且您应该这样做!)
它适用于受 PW 保护的数据库,您只需在参数中传递身份验证
这比 find/forEach/insert 快得多,在我的情况下是 2 分钟 vs 2 小时
使用 --username 而不是 --password 传入数据库的用户名以提示输入密码。最好不要将密码放在命令行上(最终将其保存到 .bash_history 或类似文件中)
次要:我在由 some_database 命名的子文件夹中找到了该文件,因此这对我有用: mongorestore -d some_other_db -c some_or_other_collection dump/some_database/some_collection.bson
S
Sergey Vyacheslavovich Brunov

目前 MongoDB 中没有可以执行此操作的命令。请注意JIRA ticket with related feature request

您可以执行以下操作:

db.<collection_name>.find().forEach(function(d){ db.getSiblingDB('<new_database>')['<collection_name>'].insert(d); });

请注意,这样,两个数据库需要共享同一个 mongod 才能工作。

除此之外,您可以对一个数据库中的集合进行 mongodump,然后将集合 mongorestore 到另一个数据库。


请注意,如果您 copy in the JS shell 在此过程中将 BSON 文档解码为 JSON,那么某些文档可能会导致类型更改。 mongodump/mongorestore 通常是更好的方法。
同意。这更像是一个玩弄外壳的有趣建议。另外,它不会带来索引。如果我这样做,我会每次都执行 mongodump/mongorestore。
谢谢。请注意,您的代码中有错字,没有关闭 getSiblingDB 函数。这是更正后的代码: db..find().forEach(function(d){ db.getSiblingDB('')[''].insert(d); });
这对于在测试运行之间从黄金副本重置测试 mongodb 非常有效。而不是硬编码集合名称,您可以使用 db.getCollection(name).find().forEach 对要复制的所有集合名称执行 for 循环,并提供具有 db.getSiblingDB("otherdb") 的函数。获取集合(名称)。插入(d)。
这对于大型收藏品是否有效?
S
Saim Ehsan

实际上,有一个命令可以将集合从一个数据库移动到另一个数据库。它只是不称为“移动”或“复制”。

要复制一个集合,您可以在同一个数据库上克隆它,然后移动克隆的集合。

克隆:

> use db1
switched to db db1

> db.source_collection.find().forEach(
      function(x){
          db.collection_copy.insert(x)
      }
  );

移动:

> use admin
switched to db admin

> db.runCommand(
      {
          renameCollection: 'db1.source_collection',
          to              : 'db2.target_collection'
      }
  );

其他答案更适合复制集合,但如果您要移动它,这尤其有用。


Thx 效果很好!只需要在 'db1.source_collection' 中加上一个撇号
而不是“使用管理员”后跟“db.runCommand(...”您可以只执行一个命令,“db.adminCommand(...”
这不适用于您无法重命名的共享集合。
逐个文档复制集合将需要很长时间!
w
wayne

我会滥用 mongo cli mongo doc 中的连接功能。这意味着您可以启动一个或多个连接。如果您想将客户集合从 test 复制到同一服务器中的 test2。首先你启动 mongo shell

use test
var db2 = connect('localhost:27017/test2')

正常查找并将前 20 条记录复制到 test2。

db.customer.find().limit(20).forEach(function(p) { db2.customer.insert(p); });

或按某些标准过滤

db.customer.find({"active": 1}).forEach(function(p) { db2.customer.insert(p); });

只需将 localhost 更改为 IP 或主机名即可连接到远程服务器。我使用它将测试数据复制到测试数据库进行测试。


正如我对 Jason 的建议所评论的那样,请注意,如果您在 JS shell 中复制,则 BSON 文档在此过程中会被解码为 JSON,因此某些文档可能会导致类型更改。与 Limitations of eval 有类似的注意事项,这将是在数据库之间(尤其是在同一台服务器上)复制大量数据的较慢过程。所以 mongodump/mongorestore FTW :)。
e
es cologne

如果在两个远程 mongod 实例之间,请使用

{ cloneCollection: "<collection>", from: "<hostname>", query: { <query> }, copyIndexes: <true|false> } 

请参阅http://docs.mongodb.org/manual/reference/command/cloneCollection/


copyIndexes 选项字段实际上不受尊重。索引总是被复制的。请参阅 SERVER-11418
将其包装在 db.runCommand() 即 db.runCommand({ cloneCollection: "", from: "", query: { } })
这如何用于从一个远程 mongo 到另一个远程 mongo 的增量更新?
我整天都将用户数据添加到一个 mongo 实例中。在一天结束时,我需要将新添加的行转移到另一个 mongo 实例。如何做到这一点?
@NishantKumar 尝试在查询中设置:{} 此代码:$where: function() { today = new Date(); // today.setHours(0,0,0,0);返回 (this._id.getTimestamp() >= 今天) 。请参阅stackoverflow.com/questions/42456375/…
f
ffflabs

我通常会这样做:

use sourcedatabase;
var docs=db.sourcetable.find();
use targetdatabase;
docs.forEach(function(doc) { db.targettable.insert(doc); });

这段代码一个一个地插入文档,会很慢!整个集合需要适合您的 RAM。
n
nametal

对于大型集合,您可以使用 Bulk.insert()

var bulk = db.getSiblingDB(dbName)[targetCollectionName].initializeUnorderedBulkOp();
db.getCollection(sourceCollectionName).find().forEach(function (d) {
    bulk.insert(d);
});
bulk.execute();

这将节省大量时间。就我而言,我正在复制包含 1219 个文档的集合:iter vs Bulk (67 secs vs 3 secs)


这更好,更高效,更少的数据库,适用于任何大小的数据集。
如果您对超过 300k 条记录执行此操作,则可能需要在 find 之后和 foreach 之前添加一个 .limit(300000)。否则系统可能会锁定。为了安全起见,我通常将批量更改限制在 100k 左右。根据计数和限制将整个事物包装在 for 循环中。
我们应该插入(一个)还是更喜欢批量插入许多?
整个集合需要适合您的 RAM,这可能是一个限制。
A
Alexander Makarov

您可以使用聚合框架来解决您的问题

db.oldCollection.aggregate([{$out : "newCollection"}])

应该注意的是,oldCollection 中的索引不会复制到 newCollection 中。


还应注意,任何现有的 newCollection 在插入新数据之前都会被删除。
p
prasad_

有不同的方法来做收藏副本。请注意,复制可能发生在同一数据库、不同数据库、分片数据库或 mongod 实例中。一些工具可以有效地用于大型集合复制。

使用 $merge 进行聚合: 将聚合管道的结果写入指定的集合。请注意,复制可以跨数据库发生,甚至是分片集合。创建一个新集合或替换现有集合。 4.2 版中的新功能。示例:db.test.aggregate([ { $merge: { db: "newdb", coll: "newcoll" }} ])

使用 $out 进行聚合: 将聚合管道的结果写入指定的集合。请注意,复制只能发生在同一个数据库中。创建一个新集合或替换现有集合。示例:db.test.aggregate([ { $out: "newcoll" } ])

mongoexport 和 mongoimport: 这些是命令行工具。 mongoexport 生成集合数据的 JSON 或 CSV 导出。使用 mongoimport 将导出的输出用作目标集合的源。

mongodump 和 mongorestore: 这些是命令行工具。 mongodump 实用程序用于创建数据库或集合内容的二进制导出。 mongorestore 程序将数据从由 mongodump 创建的二进制数据库转储加载到目标中。

db.cloneCollection(): 将集合从远程 mongod 实例复制到当前 mongod 实例。自 4.2 版起已弃用。

db.collection.copyTo():将集合中的所有文档复制到新的集合中(在同一数据库中)。自 3.0 版起已弃用。从版本 4.2 开始,MongoDB 这条命令无效。

注意: 除非说上述命令从 mongo shell 运行。

参考: The MongoDB Manual

您还可以使用喜欢的编程语言(例如,Java)或环境(例如,NodeJS),使用适当的驱动程序软件编写程序来执行复制 - 这可能涉及使用查找和插入操作或其他方法。也可以从 mongo shell 执行此查找插入。

您还可以使用 MongoDB Compass 等 GUI 程序进行收集复制。


W
Wernfried Domscheit

令人难以置信的是,对于极其缓慢的逐个数据副本给予了多少赞成票。

正如其他答案中给出的那样,最快的解决方案应该是mongodump / mongorestore。无需将转储保存到本地磁盘,您可以将转储直接通过管道传输到 mongorestore:

mongodump --db=some_database --collection=some_collection --archive=- | mongorestore --nsFrom="some_database.some_collection" --nsTo="some_or_other_database.some_or_other_collection" --archive=-

如果您运行分片集群,则默认情况下不会对新集合进行分片。所有数据最初都写入您的主分片。这可能会导致磁盘空间出现问题,并为您的集群增加 balancing 的负载。在导入数据之前,最好像这样pre-split您的集合:

sh.shardCollection("same_or_other_database.same_or_other_collection", { <shard_key>: 1 });
db.getSiblingDB("config").getCollection("chunks").aggregate([
   { $match: { ns: "some_database.some_collection"} },
   { $sort: { min: 1 } },
   { $skip: 1 }
], { allowDiskUse: true }).forEach(function (chunk) {
   sh.splitAt("same_or_other_database.same_or_other_collection", chunk.min)
})

S
Sammaye

我知道这个问题已经得到解答,但是我个人不会回答@JasonMcCays,因为游标流式传输,如果仍在使用该集合,这可能会导致无限游标循环。相反,我会使用快照():

http://www.mongodb.org/display/DOCS/How+to+do+Snapshotted+Queries+in+the+Mongo+Database

@bens 答案也是一个很好的答案,不仅适用于集合的热备份,而且 mongorestore 不需要共享同一个 mongod。


V
Vajk Hermecz

这可能只是一个特例,但是对于具有两个随机字符串字段(长度为 15-20 个字符)的 100k 文档的集合,使用哑 mapreduce 的速度几乎是 find-insert/copyTo 的两倍:

db.coll.mapReduce(function() { emit(this._id, this); }, function(k,vs) { return vs[0]; }, { out : "coll2" })

v
vbhakta

使用 pymongo,您需要在同一个 mongod 上拥有两个数据库,我做了以下操作:

db = 原始数据库 db2 = 要复制到的数据库

cursor = db["<collection to copy from>"].find()
for data in cursor:
    db2["<new collection>"].insert(data)

如果数据量很大,这将花费很多时间。或者,您可以使用 bulk_insert
是的,这只是我发现为我工作的一种快速而肮脏的方式,我的数据库不是太大,但也不小,也不需要太长时间,但是是的,你是对的。
你好@vbhakta,不幸的是光标为我返回空数组。我做了什么:cursor = db['my-node-js'].collectioName.find()。你可以理解 my-node-js 是数据库名称。我执行 print(cursor.toArray()) 时得到的是 '[ ]' 并且 print(cursor.count()) 打印 0。
U
Uday Krishna

如果 RAM 不是问题,则使用 insertManyforEach 循环快得多。

var db1 = connect('<ip_1>:<port_1>/<db_name_1>')
var db2 = connect('<ip_2>:<port_2>/<db_name_2>')

var _list = db1.getCollection('collection_to_copy_from').find({})
db2.collection_to_copy_to.insertMany(_list.toArray())

D
Dan Dascalescu

这不会解决您的问题,但 mongodb shell 有一个 copyTo 方法,可将集合复制到同一数据库中的另一个

db.mycoll.copyTo('my_other_collection');

它还从 BSON 转换为 JSON,因此正如其他人所说,mongodump/mongorestore 是最好的方法。


出色的。遗憾的是,Mongo shell reference 似乎没有提到这种方法。
是的,我知道,但是 MongoDB shell 很棒,如果您键入 db.collname.[TAB],您将看到集合对象上的所有可用方法。此技巧适用于所有其他对象。
问题是这些命令缺乏帮助!能够看到代码是很有用的,尽管通过省略方法调用的括号。
遗憾的是,该命令自 3.0 版以来已被弃用。
T
Timo

万一有些heroku用户在这里绊倒了,像我一样想将一些数据从临时数据库复制到生产数据库,反之亦然,这就是你如何非常方便地做到这一点(注意我希望那里没有错别字,不能在atm检查它。,我会尽快确认代码的有效性):

to_app="The name of the app you want to migrate data to"
from_app="The name of the app you want to migrate data from"
collection="the collection you want to copy"
mongohq_url=`heroku config:get --app "$to_app" MONGOHQ_URL`
parts=(`echo $mongohq_url | sed "s_mongodb://heroku:__" | sed "s_[@/]_ _g"`)
to_token=${parts[0]}; to_url=${parts[1]}; to_db=${parts[2]}
mongohq_url=`heroku config:get --app "$from_app" MONGOHQ_URL`
parts=(`echo $mongohq_url | sed "s_mongodb://heroku:__" | sed "s_[@/]_ _g"`)
from_token=${parts[0]}; from_url=${parts[1]}; from_db=${parts[2]}
mongodump -h "$from_url" -u heroku -d "$from_db" -p"$from_token" -c "$collection" -o col_dump
mongorestore -h "$prod_url" -u heroku -d "$to_app" -p"$to_token" --dir col_dump/"$col_dump"/$collection".bson -c "$collection"

c
crantok

您可以随时使用 Robomongo。从 v0.8.3 开始,有一个工具可以通过右键单击集合并选择“将集合复制到数据库”来执行此操作

有关详细信息,请参阅http://blog.robomongo.org/whats-new-in-robomongo-0-8-3/

此功能是 removed in 0.8.5,因为它有缺陷,因此如果您想试用它,您必须使用 0.8.3 或 0.8.4。


Robomongo 的这个功能仍然不稳定。这是一个 50/50 的机会让它发挥作用。
这似乎已从 0.8.5 中删除
A
Ahmad Hamzavi

通过单击数据库、集合或特定集合下载链接,使用具有导出和导入工具的“Studio3T for MongoDB”:https://studio3t.com/download/


H
Hamza Afridi

这里有很多正确的答案。对于大型集合,我会以管道方式选择 mongodumpmongorestore

mongodump --db fromDB --gzip --archive | mongorestore --drop --gzip --archive --nsFrom "fromDB.collectionName" --nsTo "toDB.collectionName"

虽然如果我想做快速复制,它很慢但它有效:

use fromDB 
db.collectionName.find().forEach(function(x){
   db.getSiblingDB('toDB')['collectionName'].insert(x);
});"

我尝试了 mongorestore --uri mongodb+srv://iser:pass@test.sub1.mongodb.net --nsFrom "weblog.contractors" --nsTo "weblog.contractors_temp",但 它只是试图覆盖整个博客数据库。 在 mongorestore 之前我做了:mongodump --uri mongo+srv://asd:asda@asd.asd.com/weblog。请小心。
C
Cache Staheli

就我而言,我必须在新集合中使用旧集合中的属性子集。所以我最终在新集合上调用 insert 时选择了这些属性。

db.<sourceColl>.find().forEach(function(doc) { 
    db.<newColl>.insert({
        "new_field1":doc.field1,
        "new_field2":doc.field2,
        ....
    })
});`

N
Nestor

要将集合 (myCollection1) 从一个数据库复制到 MongoDB 中的另一个数据库,

**Server1:**
myHost1.com 
myDbUser1
myDbPasword1
myDb1
myCollection1

outputfile:
myfile.json 

**Server2:**
myHost2.com 
myDbUser2
myDbPasword2
myDb2
myCollection2 

你可以这样做:

mongoexport  --host myHost1.com --db myDb1 -u myDbUser1  -p myDbPasword1 --collection myCollection1   --out  myfile.json 

然后:

mongoimport  --host myHost2.com --db myDb2 -u myDbUser2  -p myDbPasword2 --collection myCollection2   --file myfile.json 

另一种情况,使用 CSV 文件:

Server1:
myHost1.com 
myDbUser1
myDbPasword1
myDb1
myCollection1
fields.txt
    fieldName1
    fieldName2

outputfile:
myfile.csv

Server2:
myHost2.com 
myDbUser2
myDbPasword2
myDb2
myCollection2

你可以这样做:

mongoexport  --host myHost1.com --db myDb1 -u myDbUser1  -p myDbPasword1 --collection myCollection1   --out  myfile.csv --type=csv

在 csv 文件 (name1.decimal(),name1.string()..) 中添加 clolumn 类型,然后:

mongoimport  --host myHost2.com --db myDb2 -u myDbUser2  -p myDbPasword2 --collection myCollection2   --file myfile.csv --type csv --headerline --columnsHaveTypes

M
Michael

这可以使用 Mongo 的 db.copyDatabase 方法完成:

db.copyDatabase(fromdb, todb, fromhost, username, password)

参考:http://docs.mongodb.org/manual/reference/method/db.copyDatabase/


OP 想要复制一个集合——而不是整个数据库。