Bir koleksiyon MongoDB'de bir veritabanından diğerine nasıl kopyalanır


221

Bunu yapmanın kolay bir yolu var mı?


40
Kabul edilen cevap 2012'de tartışmasız en iyi yöntemdi, ancak şimdi db.cloneCollection () genellikle daha iyi bir çözümdür. Burada buna atıfta bulunan birkaç yeni cevap var, bu yüzden buraya Google'dan geldiyseniz (yaptığım gibi) tüm cevaplara bir göz atın!
Kelvin

4
Diğer cevapları da okuduğunuzdan emin olun, sadece kendi durumundaki @kelvin değil, ihtiyaçlarınızı karşıladığından emin olun
PW Kad

Yanıtlar:


206

Şu anda MongoDB'de bunu yapacak bir komut yok. Lütfen ilgili özellik talebiyle JIRA biletine dikkat edin .

Şöyle bir şey yapabilirsiniz:

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

Bununla birlikte, bunun için iki veritabanının aynı mongodu paylaşması gerekeceğini lütfen unutmayın.

Bunun yanı sıra, bir veritabanından bir koleksiyonun bir mongodump yapabilir ve daha sonra koleksiyonu diğer veritabanına mongorestore edebilirsiniz.


13
Eğer varsa o Not JS kopya kabuk bazı dokümanların tipi değişiklikleri tabi olabilir böylece BSON belgeleri sürecinde JSON çözülür. mongodump / mongorestore genellikle daha iyi bir yaklaşımdır.
Stennie

1
Kabul. Bu sadece kabuk ile oynamak için eğlenceli bir öneriydi. Ayrıca, dizinleri getirmez. Bunu yapsaydım, her seferinde mongodump / mongorestore'yu yapardım.
Jason McCay

2
Teşekkürler. Lütfen kodda bir yazım hatası olduğunu unutmayın, getSiblingDB işlevini kapatmayın. Düzeltilmiş kod şöyledir: db. <Toplama_adı> .find (). ForEach (function (d) {db.getSiblingDB ('<new_database>') ['<toplama_adı>'] .insert (d);});
Flaviu

1
bu, test çalıştırmaları arasındaki altın kopyadan bir test mongodbunu sıfırlamak için iyi çalıştı. koleksiyon adlarını sabit olarak kodlamak yerine db.getCollection (name) .find (). forEach ile kopyalamak istediğiniz tüm koleksiyon adları üzerinde bir for döngüsü yapabilirsiniz ve db.getSiblingDB ("otherdb") olan bir işlev sağlayabilirsiniz. getCollection (ad) .Bağlantı (d).
simbo1905

2
Bu büyük boyutlu koleksiyonlar için verimli midir?
Khalil Awada

284

En iyi yol bir mongodump sonra mongorestore yapmaktır.

Koleksiyonu aşağıdaki yollarla seçebilirsiniz:

mongodump -d some_database -c some_collection

[İsteğe bağlı olarak, çöplüğü ( zip some_database.zip some_database/* -r) ve scpbaşka bir yere sıkıştırın]

Sonra geri yükleyin:

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

Mevcut veriler some_or_other_collectionkorunacaktır. Bu şekilde bir koleksiyonu bir veritabanından diğerine "ekleyebilirsiniz".

2.4.3 sürümünden önce, verilerinizi kopyaladıktan sonra dizinlerinizi geri eklemeniz gerekir. 2.4.3'ten başlayarak, bu işlem otomatiktir ve ile devre dışı bırakabilirsiniz --noIndexRestore.


Görünüşe göre parola korumalı mongo örneğiniz varsa (ve yapmalısınız!) Mongodump işe yaramıyor
Luciano Camilo

3
PW korumalı DB'lerde çalışır, sadece paraşütlerdeki auth'u geçmeniz gerekir
Ben

2
Bu, bul / forEach / insert'ten çok daha hızlı, benim durumumda 2 dakika vs 2 saat
Juraj Paulo

Parola istemi almak için --username ile değil --password ile veritabanının kullanıcı adını girin. Şifreyi komut satırınıza yerleştirmemek en iyisidir (sonunda
.bash_history

Minör: benim için bu eserlerin böylece some_database tarafından adlandırılmış alt klasöründe dosya buldum: mongorestore -d some_other_db -c some_or_other_collection / some_database / some_collection.bson dökümü
Aviko

88

Aslında, olup bir komut taşımak başka bir veritabanından bir koleksiyon. Sadece "taşı" veya "kopyala" olarak adlandırılmaz.

Bir koleksiyonu kopyalamak için, aynı db üzerinde klonlayabilir, sonra klonu taşıyabilirsiniz.

Klonlama:

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

Taşımak:

> use admin
switched to db admin
> db.runCommand({renameCollection: 'db1.source_collection', to: 'db2.target_collection'}) // who'd think rename could move?

Diğer cevaplar koleksiyonu kopyalamak için daha iyidir, ancak bu özellikle taşımak istiyorsanız faydalıdır.


3
Thx harika çalışıyor! Sadece kapanış kesme işareti gerekiyor'db1.source_collection'
andrrs

4
"Admin kullan" ve ardından "db.runCommand (..." yerine "db.adminCommand (..." sadece bir komut yapabilirsiniz.
Hamid

25

Mongo cli mongo doc bağlantı işlevini kötüye kullanır . yani bir veya daha fazla bağlantı başlatabilirsiniz. müşteri koleksiyonunu aynı sunucudan testten test2'ye kopyalamak istiyorsanız. önce mongo kabuğuna başlarsınız

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

Normal bir bulgu bulun ve ilk 20 kaydı test2'ye kopyalayın.

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

veya bazı ölçütlere göre filtreleyin

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

Uzak sunucuya bağlanmak için localhost'u IP veya ana bilgisayar adı olarak değiştirmeniz yeterlidir. Bu test verilerini test için bir test veritabanına kopyalamak için kullanın.


4
Jason'ın önerisine yorum yaptığım gibi, JS kabuğuna kopyalarsanız BSON belgelerinin işlem sırasında JSON'a kodu çözüldüğünü ve bu nedenle bazı belgelerin tür değişikliklerine neden olabileceğini unutmayın. Değerlendirme sınırlamaları için benzer hususlar vardır ve bu, veritabanları arasında (özellikle aynı sunucuda) önemli miktarda veri kopyalamak için daha yavaş bir süreç olacaktır. Yani mongodump / mongorestore FTW :).
Stennie

19

İki uzak mongod örneği arasındaysa,

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

Bkz. Http://docs.mongodb.org/manual/reference/command/cloneCollection/


copyIndexesOpsiyon alanın aslında uyulmaz. Dizinler her zaman kopyalanır. Bkz SERVER-11418
Gianfranco P.

6
Bunu db.runCommand () yani db.runCommand ({cloneCollection: "<collection>", şuradan: "<hostname>", sorgu: {<query>}})
Daniel de Zwaan

Bu, bir uzak mongodan diğerine artan güncellemeler için nasıl kullanılabilir?
nishant

Gün boyunca bir mongo örneğine eklenen kullanıcı verileri var. Gün sonunda yeni eklenen satırları başka bir mongo örneğine aktarmam gerekiyor. Bu nasıl başarılabilir?
nishant

@NishantKumar sorguda ayarlamaya çalışın: {} bu kod: $ where: function () {today = new Date (); // bugün. setHours (0,0,0,0); return (this._id.getTimestamp ()> = bugün). Bkz. Stackoverflow.com/questions/42456375/… .
es cologne

18

Genellikle şunu yapardım:

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

11

büyük boyutlu koleksiyonlar için Bulk.insert () kullanabilirsiniz

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

Bu çok zaman kazandıracak . Benim durumumda, koleksiyonu 1219 belge ile kopyalıyorum: iter vs Bulk (67 sn vs 3 sn)


Bu daha iyi, daha verimli, daha az db çekiçler, her boyutta veri kümesi için çalışır.
Jeremie

Bunu 300 bin'den fazla kayıtla yapıyorsanız, bulduktan sonra ve her foreach'den önce bir .limit (300000) eklemeniz gerekebilir. Aksi takdirde sistem kilitlenebilir. Güvenlik için genellikle toplu değişiklikleri yaklaşık 100k ile sınırlıyorum. Sayıyı ve sınıra göre her şeyi for döngüsünde sarma.
triunenature

6

Sorununuzu çözmek için birleştirme çerçevesi kullanabilirsiniz

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

OldCollection dizinlerinin newCollection içinde kopyalanmayacağı belirtilmelidir.


5

Bu soruya cevap verildiğini biliyorum ancak imleç akışı nedeniyle kişisel olarak @JasonMcCays cevap vermez ve koleksiyon hala kullanılıyorsa bu sonsuz bir imleç döngüsüne neden olabilir. Bunun yerine bir snapshot () kullanırdım:

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

@bens yanıtı da iyi bir sorudur ve koleksiyonların sıcak yedeklemeleri için iyi çalışır, ancak mongorestore'nun aynı mongodu paylaşması gerekmez.


5

Bu sadece özel bir durum olabilir, ancak iki rastgele dize alanı (uzunluk 15-20 karakter) olan 100k'lık bir belge koleksiyonu için, aptal bir mapreduce kullanmak find-insert / copy'den neredeyse iki kat daha hızlıdır

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

5

Pymongo kullanarak, aynı mongod üzerinde her iki veritabanına da ihtiyacınız var, aşağıdakileri yaptım:


db = orijinal veritabanı
db2 = kopyalanacak veritabanı

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

1
veri boyutu çok büyükse bu çok zaman alacaktır. Alternatif olarak bulk_insert
nishant

1
Evet, bu benim için çalışmak için bulduğum hızlı ve kirli bir yoldu, veritabanım çok büyük değildi, ama küçük de değildi ve çok uzun sürmedi, ama evet haklısın.
vbhakta

2

Bu sorununuzu çözmez, ancak mongodb kabuğunun copyTobir koleksiyonu aynı veritabanındaki başka bir koleksiyona kopyalayan bir yöntemi vardır :

db.mycoll.copyTo('my_other_collection');

Ayrıca BSON'dan JSON'a çevirir, bu yüzden mongodump/ mongorestorediğerleri söylediği gibi gitmek için en iyi yoldur.


Mükemmel. Ne yazık ki Mongo kabuğu referansı bu yöntemden bahsetmiyor gibi görünüyor.
pgl

Evet, biliyorum, ama db.collname. [TAB] yazarsanız MongoDB kabuğu harika, toplama nesnesinde tüm kullanılabilir yöntemleri göreceksiniz. bu ipucu diğer tüm nesneler için geçerlidir.
Roberto

Sorun bu komutlar için yardım eksikliği! Parenleri bir yöntem çağrısına atlayarak kodu görebilmek yararlıdır.
pgl

2
Ne yazık ki, bu komut 3.0 sürümünden beri kullanımdan kaldırıldı.
Harry

2

RAM bir sorun değilse kullanmak döngüden insertManydaha hızlıdır 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

Bazı heroku kullanıcılarının burada tökezlemesi ve benim gibi bazı aşamaları veritabanından üretim veritabanına veya tam tersine bazı verileri kopyalamak istemesi durumunda, bunu çok kolay bir şekilde nasıl yapacağınız (NB Umarım orada yazım hatası yoktur, atm kontrol edemezsiniz., Kodun geçerliliğini en kısa sürede teyit edeceğim):

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'yu her zaman kullanabilirsiniz. V0.8.3 itibariyle, koleksiyona sağ tıklayıp "Koleksiyonu Veritabanına Kopyala" yı seçerek bunu yapabilen bir araç vardır.

Ayrıntılar için bkz. Http://blog.robomongo.org/whats-new-in-robomongo-0-8-3/

Bu özellik, buggy yapısı nedeniyle 0.8.5'te kaldırıldı, bu yüzden denemek istiyorsanız 0.8.3 veya 0.8.4 kullanmanız gerekecek.


6
Robomongo'nun bu özelliği hala kararsız. İşe yaraması için 50/50 şans.
thedp

2
Bu,
0.8.5'ten

0

Benim durumumda, yeni koleksiyonumda eski koleksiyondan bir dizi öznitelik kullanmak zorunda kaldım. Böylece yeni koleksiyonda insert çağırırken bu özellikleri seçtim.

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


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.