MongoDB에서 한 데이터베이스에서 다른 데이터베이스로 컬렉션을 복사하는 방법


221

이를 수행하는 간단한 방법이 있습니까?


40
받아 들여진 대답은 아마도 2012 년에 가장 좋은 방법 일 것입니다. 그러나 db.cloneCollection () 이 종종 더 나은 솔루션입니다. 여기에 최근 몇 가지 답변이 있습니다. 따라서 Google에서 여기 온 경우 (나처럼) 모든 답변을 살펴보십시오!
Kelvin

4
하지만 그것은 단지 @kelvin의 그 / 그녀의 상황에서 사용자의 요구에 맞는 있는지 확인뿐만 아니라 다른 답변을 읽을 수 있는지 확인
PW Kad 추가

답변:


206

현재 MongoDB에는이 작업을 수행하는 명령이 없습니다. 관련 기능 요청이 있는 JIRA 티켓을 참고하십시오 .

당신은 다음과 같은 것을 할 수 있습니다 :

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

이를 통해 두 데이터베이스가 작동하려면 동일한 mongod를 공유해야합니다.

이 외에도 한 데이터베이스에서 컬렉션의 mongodump를 수행 한 다음 컬렉션을 다른 데이터베이스로 mongorestore 할 수 있습니다.


13
당신이 경우주의 JS에 복사 쉘 일부 문서 유형 변경을 발생할 수 있도록 BSON 문서는 과정에서 JSON 디코딩된다. mongodump / mongorestore가 일반적으로 더 나은 방법입니다.
Stennie

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 (이름). 삽입 (d).
simbo1905

2
거대한 크기의 컬렉션에 효율적입니까?
Khalil Awada

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.


암호로 보호 된 몽고 인스턴스를 가지고 있다면 mongodump가 작동하지 않는 것 같습니다 (그리고 당신은해야합니다!)
Luciano Camilo

3
그것은 당신이 단지 매개 변수에서 인증을 통과 해야하는 PW 보호 DB에서 작동합니다
Ben

2
제 경우에는 2 분 대 2 시간 동안
Juraj Paulo

비밀번호에 대한 프롬프트를 표시하려면 --password가 아닌 --username으로 데이터베이스의 사용자 이름을 입력하십시오. 명령 행에 비밀번호를 입력하지 않는 것이 가장 좋습니다 (.bash_history 또는 이와 유사한 이름으로 저장)
Chanoch

마이너 : 나는 나를 위해이 작품 때문에 some_database에 의해 명명 된 하위 폴더에있는 파일을 발견 mongorestore -d some_other_db -c some_or_other_collection / 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
"admin 사용"다음에 "db.runCommand (...") 대신 "db.adminCommand (..."명령 하나만 수행 할 수 있습니다.
Hamid

25

mongo cli mongo doc 에서 연결 기능을 남용합니다 . 즉, 하나 이상의 연결을 시작할 수 있습니다. 동일한 서버에서 고객 콜렉션을 테스트에서 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 :).
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>", from : "<hostname>", query : {<query>}})
Daniel de Zwaan

한 원격 몽고에서 다른 원격 몽고로의 증분 업데이트에 어떻게 이것을 사용할 수 있습니까?
nishant

하루 종일 하나의 몽고 인스턴스에 사용자 데이터가 추가되었습니다. 하루가 끝나면 새로 추가 된 행을 다른 몽고 인스턴스로 전송해야합니다. 이것이 어떻게 달성 될 수 있습니까?
nishant

@NishantKumar는 쿼리에서 설정하려고 시도합니다 : {}이 코드 : $ where : function () {today = new Date (); // today.setHours (0,0,0,0); return (this._id.getTimestamp ()> = today). stackoverflow.com/questions/42456375/…를 참조하십시오 .
es cologne

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)를 추가해야 할 수 있습니다. 그렇지 않으면 시스템이 잠길 수 있습니다. 안전을 위해 일반적으로 대량 변경을 약 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 answer도 좋은 답변이며 컬렉션의 핫 백업뿐만 아니라 mongorestore는 동일한 mongod를 공유 할 필요가 없습니다.


5

이것은 특별한 경우 일 수 있지만 두 개의 임의 문자열 필드 (길이는 15-20 자)가있는 100k 문서 모음의 경우 바보 같은 mapreduce를 사용하면 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

1
예, 이것은 저에게 도움이되는 빠르고 더러운 방법이었습니다. 데이터베이스가 너무 크지 않았지만 작지 않았으며 너무 오래 걸리지 않았습니다. 그렇습니다. 그렇습니다.
vbhakta

2

이렇게하면 문제가 해결되지 않지만 mongodb 셸에는 copyTo컬렉션을 동일한 데이터베이스의 다른 컬렉션으로 복사하는 방법이 있습니다 .

db.mycoll.copyTo('my_other_collection');

또한 JSON에 BSON에서, 그래서 변환 mongodump/ mongorestore다른 사람이 말했듯이, 갈 수있는 가장 좋은 방법입니다.


우수한. 슬프게도 Mongo 쉘 참조 는이 방법을 언급하지 않는 것 같습니다.
pgl

예, 알지만 MongoDB 셸은 훌륭합니다. db.collname. [TAB]을 입력하면 컬렉션 객체에 사용 가능한 모든 메소드가 표시됩니다. 이 팁은 다른 모든 개체에 적용됩니다.
Roberto

문제는 명령에 대한 도움이 부족하다는 것입니다! 메소드 호출에 대한 parens를 생략하여 코드를 볼 수 있으면 유용합니다.
pgl

2
안타깝게도이 명령은 버전 3.0부터 더 이상 사용되지 않습니다.
Harry

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 사용자가 여기에서 걸려 넘어져서 스테이징 데이터베이스에서 프로덕션 데이터베이스로 또는 그 반대로 일부 데이터를 복사하려는 경우 여기에 매우 편리하게 수행하는 방법이 있습니다 (NB에는 오타가 없기를 바랍니다. 가능한 한 코드의 유효성을 확인하려고 시도합니다.)

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

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.