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


221

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


40
可以接受的答案可以说是2012年的最佳方法,但是现在db.cloneCollection()通常是一个更好的解决方案。这里有一些与此有关的最新答案,因此,如果您像我一样从Google来到这里,请查看所有答案!
开尔文2015年

4
确保同时阅读其他答案,以确保它满足您的需求,而不仅仅是@kelvin的情况
PW Kad

Answers:


206

目前,MongoDB中没有命令可以执行此操作。请注意JIRA票证及相关功能要求

您可以执行以下操作:

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

请注意,为此,两个数据库需要共享相同的mongod才能起作用。

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


13
请注意,如果您在JS Shell中进行复制,则 BSON文档将在此过程中解码为JSON,因此某些文档可能会导致类型更改。mongodump / mongorestore通常是更好的方法。
Stennie 2012年

1
同意 那只是一个玩弄外壳的有趣建议。另外,它不会带来索引。如果执行此操作,则每次都会执行mongodump / mongorestore。
杰森·麦凯2012年

2
谢谢。请注意,代码中有错别字,没有关闭getSiblingDB函数。这是更正后的代码:db。<collection_name> .find()。forEach(function(d){db.getSiblingDB('<new_database>')['<< collection_name>']。insert(d);});
Flaviu 2012年

1
这对于从两次测试运行之间的黄金副本重置测试mongodb效果很好。无需对集合名称进行硬编码,您可以使用db.getCollection(name).find()。forEach对要复制的所有集合名称进行for循环,并提供一个具有db.getSiblingDB(“ otherdb”)的函数。 getCollection(name).insert(d)。
simbo1905

2
这对于大量收藏有效吗?
哈利勒·阿瓦达

284

最好的方法是先进行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似乎无法正常工作(您应该这样做!)
Luciano Camilo

3
它适用于PW保护你只需要通过身份验证的PARAMS的DB

2
这比查找/的forEach /插入快得多,在我的情况2分钟VS2小时
尤拉伊·保罗

使用--username(而不是--password)传递数据库的用户名,以提示输入密码。最好不要将密码放在命令行中(最终将其保存到.bash_history或类似文件中)
Chanoch

辅修:我发现some_database命名的子文件夹中的文件所以这个工作对我来说:mongorestore -d some_other_db -c some_or_other_collection转储/ some_database / some_collection.bson
Aviko

88

其实,有一个命令移动从一个数据库收集到另一个。它只是不被称为“移动”或“复制”。

要复制集合,可以将其克隆到同一数据库上,然后移动克隆。

克隆:

> use 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'}) // who'd think rename could move?

其他答案更适合于复制集合,但是如果您要移动它,则特别有用。


3
Thx很棒!只需在'db1.source_collection'

4
您可以只执行一个命令“ db.adminCommand(...”),而不是“ use admin”后跟“ db.runCommand(...”)
Hamid

25

我会滥用mongo cli mongo doc中的connect函数。这样就可以启动一个或多个连接。如果要将客户集合从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或主机名即可连接到远程服务器。我使用它来将测试数据复制到测试数据库以进行测试。


4
正如我评论Jason的建议一样,请注意,如果在JS Shell中进行复制,则BSON文档在此过程中将解码为JSON,因此某些文档可能会导致类型更改。与评估限制有类似的考虑,这将是在数据库之间(尤其是在同一服务器上)复制大量数据的较慢过程。所以mongodump / mongorestore FTW :)。
Stennie

19

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

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

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


copyIndexes选项字段实际上是不尊重。索引始终被复制。请参阅SERVER-11418
Gianfranco P.

6
将其包装在db.runCommand()中,即db.runCommand({cloneCollection:“ <collection>”,来自:“ <hostname>”,查询:{<query>}})
Daniel de Zwaan 2014年

如何将其用于从一个远程mongo到另一远程mongo的增量更新?
nishant

我整天将用户数据添加到一个mongo实例中。最终,我需要将新添加的行转移到另一个mongo实例。如何做到这一点?
nishant

@NishantKumar尝试在查询中设置:{}此代码:$ where:function(){today = new Date(); // today.setHours(0,0,0,0); 返回(this._id.getTimestamp()> =今天)。参见stackoverflow.com/questions/42456375/…
es科隆

18

我通常会这样做:

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

11

对于庞大的集合,可以使用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秒vs 3秒)


这是一种更好,更有效的方法,可以减少db的负担,适用于任何大小的数据集。
Jeremie

如果要对超过300k条记录进行此操作,则可能需要在查找之后和foreach之前添加.limit(300000)。否则系统可能会锁定。为了安全起见,我通常将批量更改限制在10万左右。根据计数和限制将整个对象包装在for循环中。
triunenature



5

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

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

5

使用pymongo,您需要将两个数据库都放在同一个mongod上,我做了以下工作:


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

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

1
如果数据量巨大,则将花费大量时间。另外,您也可以使用bulk_insert
nishant '18

1
是的,这只是我发现对我有用的一种快速而肮脏的方式,我的数据库不是太大,但是也不小,也不需要花费太长时间,但是是的,您是正确的。
vbhakta

2

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

db.mycoll.copyTo('my_other_collection');

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


优秀的。遗憾的是,Mongo Shell参考似乎没有提到此方法。
pgl

是的,我知道,但是MongoDB shell很棒,如果您键入db.collname。[TAB],您将在collection对象上看到所有可用的方法。本技巧适用于所有其他对象。
罗伯托

问题是这些命令缺少帮助!尽管可以省略方法调用的括号,但是能够看到代码是很有用的。
pgl

2
遗憾的是,此命令自版本3.0起已被弃用。
哈里

2

如果RAM不是问题,则使用insertMany方法比forEach循环要快。

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())

1

如果某些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"

1

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

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

由于此功能存在缺陷,因此已在0.8.5中将其删除,因此,如果要试用该功能,则必须使用0.8.3或0.8.4。


6
Robomongo的此功能仍然不稳定。这是一个50/50的机会使其起作用。
thedp 2014年

2
这似乎已从0.8.5中删除
-Carasel

0

就我而言,我必须在新集合中使用旧集合的属性子集。因此,我最终在对新集合调用insert时选择了那些属性。

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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.