MongoDBでデータベース間でコレクションをコピーする方法


221

これを行う簡単な方法はありますか?


40
受け入れられた答えは間違いなく2012年の時点で最良の方法でしたが、現在はdb.cloneCollection()がより優れたソリューションであることがよくあります。これを参照する最近の回答がいくつかあるので、Googleからここに来た場合(私が行ったように)、すべての回答を見てください!
ケルビン

4
@kelvinの状況だけでなく、他の回答も読んで、ニーズに合っていることを確認してください
PW Kad

回答:


206

現時点では、MongoDBにはこれを行うコマンドはありません。JIRAチケットと関連する機能リクエストに注意してください。

あなたは次のようなことをすることができます:

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

これを使用する場合、これが機能するためには、2つのデータベースが同じmongodを共有する必要があることに注意してください。

これに加えて、1つのデータベースからコレクションのmongodumpを実行してから、コレクションを他のデータベースにmongorestoreすることができます。


13
JSシェルでコピーする場合、BSONドキュメントはプロセス中にJSONにデコードされるため、一部のドキュメントではタイプが変更される可能性があることに注意してください。一般に、mongodump / mongorestoreがより優れたアプローチです。
ステニー

1
同意した。それは、シェルをいじるのはもっと楽しい提案でした。さらに、それはインデックスをもたらしません。これを行っている場合、毎回mongodump / mongorestoreを実行します。
Jason McCay

2
ありがとう。getSiblingDB関数を閉じるのではなく、コードにタイプミスがあることに注意してください。修正されたコードは次のとおりです。db。<collection_name> .find()。forEach(function(d){db.getSiblingDB( '<new_database>')['<collection_name>']。insert(d);});
Flaviu

1
これは、テスト実行の間のゴールデンコピーからテストmongodbをリセットするのに役立ちました。コレクション名をハードコーディングする代わりに、db.getCollection(name).find()。forEachでコピーするすべてのコレクション名に対してforループを実行し、db.getSiblingDB( "otherdb")を持つ関数を指定できます。 getCollection(name).insert(d)。
simbo1905

2
これは巨大なサイズのコレクションに対して効率的ですか?
Khalil

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で保護されたDBで動作し、パラメーターで認証を渡すだけです
Ben

2
これは、find / forEach / insertよりもはるかに高速です。私の場合は、2分から2時間です
Juraj Paulo

--usernameでデータベースのユーザー名を渡しますが、-passwordではなく、パスワードのプロンプトを取得します。コマンドラインにパスワードを入力しないことをお勧めします(最終的には.bash_historyなどに保存します)
Chanoch

マイナー:some_databaseという名前のサブフォルダーにファイルが見つかったので、これは私にとってはうまくいきました:mongorestore -d some_other_db -c some_or_other_collection dump / some_database / some_collection.bson
Aviko

88

実際に、あるデータベースから別のデータベースにコレクションを移動するコマンドがあります。「移動」や「コピー」とは呼ばれません。

コレクションをコピーするには、同じdbにコレクションを複製してから、その複製を移動します。

複製するには:

> 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'
andrrs

4
代わりに続いて「利用管理」の「db.runCommand(...」あなたはただ一つのコマンド、「db.adminCommand(...」を行うことができます
ハミド

25

mongo cli mongo docの接続機能を悪用します。つまり、1つ以上の接続を開始できます。同じサーバーでテストからtest2に顧客コレクションをコピーする場合。最初にモンゴシェルを起動します

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シェルでコピーすると、プロセス中にBSONドキュメントがJSONにデコードされるため、一部のドキュメントで型の変更が発生する可能性があることに注意してください。evalの制限についても同様の考慮事項があり、これはデータベース間(特に同じサーバー上)で大量のデータをコピーする場合の処理​​が遅くなります。したがって、mongodump / mongorestore FTW :)。
ステニー

19

2つのリモート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>"、from: "<hostname>"、query:{<query>}})
Daniel de Zwaan

これは、あるリモートmongoから別のリモートmongoへの増分更新にどのように使用できますか?
nishant

1日を通して1つのmongoインスタンスにユーザーデータが追加されています。1日の終わりに、新しく追加した行を別のmongoインスタンスに転送する必要があります。どうすればこれを達成できますか?
nishant

@NishantKumarはクエリで設定しようとします:{}このコード:$ where:function(){今日=新しい日付(); //today.setHours(0,0,0,0); return(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秒)


これは、より良い、より効率的な、より少ないデータベースをハンマーで打つ、あらゆるサイズのデータ​​セットで機能します。
ジェレミー

300kを超えるレコードを使用してこれを行う場合は、検索の後で、foreachの前に.limit(300000)を追加する必要がある場合があります。そうしないと、システムがハングアップする可能性があります。安全のため、私は通常、一括変更を約100kに制限しています。カウントと制限に基づいてforループで全体をラップします。
triunenature

6

集計フレームワークを使用して問題を解決できます

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

oldCollectionのインデックスはnewCollectionにコピーされないことに注意してください。


5

私はこの質問に回答したことを知っていますが、カーソルがストリームし、コレクションがまだ使用されている場合、これが無限カーソルループを引き起こす可能性があるため、個人的に@JasonMcCaysの回答は行いません。代わりに、snapshot()を使用します。

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

@bensの回答も良い回答であり、コレクションのホットバックアップに適しているだけでなく、mongorestoreが同じmongodを共有する必要もありません。


5

これは特別なケースかもしれませんが、2つのランダムな文字列フィールド(長さが15〜20文字)の100k文書のコレクションの場合、ダムmapreduceを使用すると、find-insert / copyToのほぼ2倍の速度になります。

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

1
はい、これは私のために機能することがわかった迅速で汚い方法でした、私のデータベースは大きすぎず、小さすぎず、あまり長くはかかりませんでしたが、そうです。
vbhakta 2018年

2

これで問題は解決しませんが、mongodbシェルには、同じデータベース内のcopyTo別のコレクションにコレクションをコピーするメソッドがあります

db.mycoll.copyTo('my_other_collection');

また、BSONからJSONに変換されるため、他の人が言っているように、mongodump/ mongorestoreが最適な方法です。


優れた。悲しいことに、Mongo シェルのリファレンスでは、このメソッドについて言及されていないようです。
pgl 2013

はい、わかりますが、MongoDBシェルは素晴らしいです。db.collname。[TAB]と入力すると、コレクションオブジェクトで使用可能なすべてのメソッドが表示されます。このヒントは、他のすべてのオブジェクトで機能します。
ロベルト

問題は、これらのコマンドのヘルプがないことです。メソッドの呼び出しで括弧を省略しても、コードを確認できると便利です。
pgl 2013

2
悲しいことに、このコマンドはバージョン3.0以降廃止されました。
Harry

2

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

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,
        ....
    })
});`


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.