วิธีคัดลอกคอลเล็กชันจากฐานข้อมูลหนึ่งไปยังอีกฐานข้อมูลใน MongoDB


221

มีวิธีง่าย ๆ ในการทำเช่นนี้?


40
คำตอบที่ได้รับการยอมรับนั้นเป็นวิธีที่ดีที่สุดในปี 2012 แต่ตอนนี้db.cloneCollection ()มักเป็นทางออกที่ดีกว่า มีคำตอบล่าสุดอีกสองสามข้อที่อ้างถึงนี้ดังนั้นหากคุณมาที่นี่จาก Google (อย่างที่ฉันทำ) มาดูคำตอบทั้งหมด!
เคลวิน

4
ตรวจสอบให้แน่ใจว่าได้อ่านคำตอบอื่น ๆ เช่นกัน แต่เพื่อให้แน่ใจว่ามันเหมาะกับความต้องการของคุณไม่ได้เป็นเพียง @kelvin 'ใน / สถานการณ์ของเขาและเธอ
PW กาด

คำตอบ:


206

ในตอนนี้ไม่มีคำสั่งใน MongoDB ที่จะทำเช่นนี้ โปรดทราบตั๋วจิระที่มีการร้องขอคุณลักษณะที่เกี่ยวข้อง

คุณสามารถทำสิ่งที่ชอบ:

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

โปรดทราบว่าด้วยสิ่งนี้ฐานข้อมูลทั้งสองจะต้องใช้ Mongo เดียวกันร่วมกันเพื่อใช้งานได้

นอกจากนี้คุณสามารถทำ 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 (ชื่อ) .find (). forEach และจัดหาฟังก์ชันที่มี db.getSiblingDB ("otherdb") getCollection (ชื่อ) .insert (ง)
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 จะไม่ทำงานหากคุณมีอินสแตนซ์ของ mongo ที่มีการป้องกันด้วยรหัสผ่าน (และคุณควรจะ!)
Luciano Camilo

3
มันใช้งานได้กับฐานข้อมูลที่มีการป้องกัน PW คุณเพียงแค่ต้องผ่านการรับรองความถูกต้องใน params
Ben

2
นี้เร็วกว่าการค้นหา / forEach / insert ในกรณีของฉัน 2 นาทีเทียบกับ 2 ชั่วโมง
Juraj เปาโล

ส่งชื่อผู้ใช้สำหรับฐานข้อมูลด้วย - ชื่อผู้ใช้ แต่ไม่ใช่ - รหัสผ่านเพื่อรับพร้อมท์รหัสผ่าน เป็นการดีที่สุดที่จะไม่ใส่รหัสผ่านในบรรทัดคำสั่งของคุณ (จบลงด้วยการบันทึกลงใน. 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
ขอบคุณมาก! เพียงแค่ต้องการเครื่องหมาย'db1.source_collection'
อะโพสโทร

4
แทน "ใช้ผู้ดูแลระบบ" ตามด้วย "db.runCommand (... " คุณสามารถทำได้เพียงคำสั่งเดียว "db.adminCommand (... "
Hamid

25

ฉันจะละเมิดฟังก์ชั่นการเชื่อมต่อใน Mongo CLI Mongo doc ดังนั้นหมายความว่าคุณสามารถเริ่มต้นการเชื่อมต่อหนึ่งรายการขึ้นไป ถ้าคุณต้องการคัดลอกคอลเลกชันของลูกค้าจากการทดสอบไปยัง 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 เชลล์เอกสาร BSON จะถูกถอดรหัสเป็น JSON ในระหว่างกระบวนการดังนั้นเอกสารบางอย่างอาจมีการเปลี่ยนแปลงประเภท มีข้อควรพิจารณาที่คล้ายกันกับข้อ จำกัด ของการประเมินผลและนี่จะเป็นกระบวนการที่ช้ากว่าสำหรับการคัดลอกข้อมูลจำนวนมากระหว่างฐานข้อมูล (โดยเฉพาะบนเซิร์ฟเวอร์เดียวกัน) ดังนั้น mongodump / mongorestore FTW :)
Stennie

19

หากระหว่างสองอินสแตนซ์ MongoS ระยะไกลใช้

{ 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

วิธีนี้สามารถใช้สำหรับการปรับปรุงที่เพิ่มขึ้นจาก Mongo ระยะไกลหนึ่งไปยังอีก
nishant

ฉันมีการเพิ่มข้อมูลผู้ใช้ลงในอินสแตนซ์ Mongo หนึ่งอินสแตนซ์ตลอดทั้งวัน ในตอนท้ายฉันต้องถ่ายโอนแถวที่เพิ่มใหม่ไปยังอินสแตนซ์ Mongo อื่น สิ่งนี้จะสำเร็จได้อย่างไร
nishant

@NishantKumar พยายามตั้งคำถาม: {} รหัสนี้: $ where: function () {today = new Date (); // today.setHours (0,0,0,0); return (this._id.getTimestamp ()> = วันนี้) ดู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 วินาทีกับ 3 วินาที)


นี่เป็นวิธีที่ดีกว่ามีประสิทธิภาพมากขึ้นค้อนน้อยกว่า db ใช้งานได้กับชุดข้อมูลทุกขนาด
Jeremie

หากคุณกำลังทำสิ่งนี้ด้วยระเบียนมากกว่า 300,000 รายการคุณอาจต้องเพิ่ม .limit (300000) หลังการค้นหาและก่อน foreach อื่นระบบอาจล็อค ฉันมักจะ จำกัด การเปลี่ยนแปลงจำนวนมากไว้ที่ประมาณ 100k เพื่อความปลอดภัย การห่อสิ่งทั้งหมดในห่วงสำหรับการนับขึ้นอยู่กับการนับและขีด จำกัด
triunenature

6

คุณสามารถใช้กรอบการรวมเพื่อแก้ไขปัญหาของคุณ

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

มันจะถูกบันทึกไว้ว่าดัชนีจาก oldCollection จะไม่ถูกคัดลอกใน newCollection


5

ฉันรู้ว่าคำถามนี้ได้รับการตอบแล้ว แต่โดยส่วนตัวแล้วฉันจะไม่ตอบ @JasonMcCays เนื่องจากข้อเท็จจริงที่ว่าเคอร์เซอร์สตรีมและสิ่งนี้อาจทำให้เกิดเคอร์เซอร์ที่ไม่สิ้นสุดหากยังคงมีการใช้คอลเลกชัน แต่ฉันจะใช้ภาพรวม ():

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

@bens คำตอบก็เป็นสิ่งที่ดีและทำงานได้ดีสำหรับการสำรองข้อมูลคอลเลกชันที่ร้อนแรงไม่เพียง แต่ mongorestore ไม่จำเป็นต้องแบ่งปัน mongod เดียวกัน


5

นี่อาจเป็นกรณีพิเศษ แต่สำหรับการรวบรวมเอกสารขนาด 100k ที่มีเขตข้อมูลสตริงแบบสุ่มสองช่อง (ความยาว 15-20 ตัวอักษร) การใช้ mapreduce แบบใบ้นั้นเร็วกว่าการค้นหา - แทรก / คัดลอกเกือบสองเท่า:

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 shell มีcopyToวิธีการที่จะทำการคัดลอกคอลเล็กชันไปยังอีกอันหนึ่งในฐานข้อมูลเดียวกัน :

db.mycoll.copyTo('my_other_collection');

นอกจากนี้ยังแปลจาก BSON เป็น JSON ดังนั้น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

ในกรณีของฉันฉันต้องใช้ชุดย่อยของคุณลักษณะจากชุดเก่าในชุดใหม่ของฉัน ดังนั้นฉันจึงเลือกคุณลักษณะเหล่านั้นในขณะที่เรียกใช้การแทรกบนคอลเล็กชันใหม่

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

0

ใช้ "Studio3T สำหรับ MongoDB" ที่มีเครื่องมือส่งออกและนำเข้าโดยคลิกที่ฐานข้อมูลคอลเลกชันหรือลิงค์ดาวน์โหลดคอลเล็กชันเฉพาะ: https://studio3t.com/download/


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.