So kopieren Sie eine Sammlung in MongoDB von einer Datenbank in eine andere


221

Gibt es eine einfache Möglichkeit, dies zu tun?


40
Die akzeptierte Antwort war 2012 wohl die beste Methode, aber jetzt ist db.cloneCollection () oft eine bessere Lösung. Es gibt hier einige neuere Antworten, die sich darauf beziehen. Wenn Sie also (wie ich) von Google hierher gekommen sind, sehen Sie sich alle Antworten an!
Kelvin

4
Lesen Sie auch die anderen Antworten, um sicherzustellen, dass sie Ihren Anforderungen entsprechen, nicht nur @kelvins in seiner / ihrer Situation
PW Kad

Antworten:


206

Im Moment gibt es in MongoDB keinen Befehl, der dies tun würde. Bitte beachten Sie das JIRA-Ticket mit der entsprechenden Funktionsanforderung .

Sie könnten so etwas tun wie:

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

Bitte beachten Sie, dass sich die beiden Datenbanken damit teilen müssen, damit dies funktioniert.

Außerdem können Sie einen Mongodump einer Sammlung aus einer Datenbank erstellen und dann die Sammlung in der anderen Datenbank speichern.


13
Beachten Sie, dass beim Kopieren in die JS-Shell die BSON-Dokumente während des Vorgangs in JSON dekodiert werden, sodass bei einigen Dokumenten möglicherweise Typänderungen auftreten können. Mongodump / Mongorestore sind im Allgemeinen der bessere Ansatz.
Stennie

1
Einverstanden. Das war eher ein lustiger Vorschlag, um mit der Muschel herumzuspielen. Außerdem würde es die Indizes nicht überbringen. Wenn ich das tun würde, würde ich jedes Mal den Mongodump / Mongorestore machen.
Jason McCay

2
Vielen Dank. Bitte beachten Sie, dass der Code einen Tippfehler enthält und die Funktion getSiblingDB nicht schließt. Hier ist der korrigierte Code: db. <Sammlungsname> .find (). ForEach (Funktion (d) {db.getSiblingDB ('<neue_Datenbank>') ['<Sammlungsname>'] .insert (d);});
Flaviu

1
Dies funktionierte gut, um einen Test-Mongodb zwischen den Testläufen von einer goldenen Kopie zurückzusetzen. Anstatt die Sammlungsnamen hart zu codieren, können Sie eine for-Schleife über alle Sammlungsnamen durchführen, die Sie mit db.getCollection (name) .find (). forEach kopieren möchten, und eine Funktion mit db.getSiblingDB ("otherdb") bereitstellen. getCollection (Name) .insert (d).
simbo1905

2
Ist dies effizient für große Sammlungen?
Khalil Awada

284

Der beste Weg ist, einen Mongodump und dann einen Mongorestore zu machen.

Sie können die Sammlung auswählen über:

mongodump -d some_database -c some_collection

[Optional können Sie den dump ( zip some_database.zip some_database/* -r) und an scpanderer Stelle komprimieren]

Dann stellen Sie es wieder her:

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

Vorhandene Daten in some_or_other_collectionbleiben erhalten. Auf diese Weise können Sie eine Sammlung von einer Datenbank an eine andere "anhängen".

Vor Version 2.4.3 müssen Sie Ihre Indizes auch wieder hinzufügen, nachdem Sie Ihre Daten kopiert haben. Ab 2.4.3 erfolgt dieser Vorgang automatisch und Sie können ihn mit deaktivieren --noIndexRestore.


Es scheint, dass Mongodump nicht funktioniert, wenn Sie eine passwortgeschützte Mongo-Instanz haben (und Sie sollten!)
Luciano Camilo

3
Es funktioniert auf PW-geschützten DBs. Sie müssen nur die Authentifizierung in den Params übergeben
Ben

2
Dies ist viel schneller als find / forEach / insert, in meinem Fall 2 Minuten vs 2 Stunden
Juraj Paulo

Übergeben Sie den Benutzernamen für die Datenbank mit --username, aber nicht --password, um eine Eingabeaufforderung für das Kennwort zu erhalten. Es ist am besten, das Passwort nicht in Ihre Befehlszeile zu schreiben (es wird schließlich in .bash_history oder ähnlichem gespeichert)
Chanoch

Minor: Ich habe die Datei im Unterordner mit dem Namen some_database gefunden, daher funktioniert dies für mich: mongorestore -d some_other_db -c some_or_other_collection dump / some_database / some_collection.bson
Aviko

88

Tatsächlich gibt es einen Befehl zum Verschieben einer Sammlung von einer Datenbank in eine andere. Es heißt einfach nicht "verschieben" oder "kopieren".

Um eine Sammlung zu kopieren, können Sie sie in derselben Datenbank klonen und dann den Klon verschieben.

Klonen:

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

Bewegen:

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

Die anderen Antworten eignen sich besser zum Kopieren der Sammlung. Dies ist jedoch besonders nützlich, wenn Sie sie verschieben möchten.


3
Thx funktioniert super! 'db1.source_collection'
Benötigt

4
Anstelle von "use admin" gefolgt von "db.runCommand (..." Sie können nur einen Befehl ausführen ", db.adminCommand (..."
Hamid,

25

Ich würde die Verbindungsfunktion in Mongo Cli Mongo Doc missbrauchen . Das bedeutet, dass Sie eine oder mehrere Verbindungen herstellen können. Wenn Sie die Kundensammlung von test nach test2 auf demselben Server kopieren möchten. Zuerst starten Sie Mongo Shell

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

Führen Sie eine normale Suche durch und kopieren Sie die ersten 20 Datensätze nach test2.

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

oder nach bestimmten Kriterien filtern

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

Ändern Sie einfach den lokalen Host in IP oder Hostname, um eine Verbindung zum Remote-Server herzustellen. Ich verwende dies, um Testdaten zum Testen in eine Testdatenbank zu kopieren.


4
Beachten Sie, dass die BSON-Dokumente beim Kopieren in die JS-Shell während des Vorgangs in JSON dekodiert werden, sodass bei einigen Dokumenten möglicherweise Typänderungen auftreten. Es gibt ähnliche Überlegungen zu Einschränkungen der Bewertung, und dies wird ein langsamerer Prozess zum Kopieren erheblicher Datenmengen zwischen Datenbanken sein (insbesondere auf demselben Server). Also mongodump / mongorestore FTW :).
Stennie

19

Wenn zwischen zwei Remote-Mongod-Instanzen, verwenden Sie

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

siehe http://docs.mongodb.org/manual/reference/command/cloneCollection/


Das copyIndexesOptionsfeld wird tatsächlich nicht berücksichtigt. Die Indizes werden immer kopiert. Siehe SERVER-11418
Gianfranco P.

6
Wickeln Sie das in db.runCommand () ein, dh db.runCommand ({cloneCollection: "<collection>", from: "<Hostname>", Abfrage: {<query>}})
Daniel de Zwaan

Wie kann dies für inkrementelle Updates von einem Remote-Mongo zu einem anderen verwendet werden?
Nishant

Ich habe Benutzerdaten, die im Laufe des Tages zu einer Mongo-Instanz hinzugefügt werden. Am Ende des Tages muss ich die neu hinzugefügten Zeilen auf eine andere Mongo-Instanz übertragen. Wie kann dies erreicht werden?
Nishant

@NishantKumar versuchen, in der Abfrage Folgendes festzulegen: {} diesen Code: $ where: function () {today = new Date (); // today.setHours (0,0,0,0); return (this._id.getTimestamp ()> = heute). Siehe stackoverflow.com/questions/42456375/… .
Es Köln

18

Normalerweise mache ich:

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

11

Für große Sammlungen können Sie Bulk.insert () verwenden.

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

Dies spart viel Zeit . In meinem Fall kopiere ich die Sammlung mit 1219 Dokumenten: iter vs Bulk (67 Sekunden vs 3 Sekunden)


Dies ist viel besser, effizienter, hämmert weniger als die Datenbank und funktioniert für jede Größe von Datensätzen.
Jeremie

Wenn Sie dies mit mehr als 300.000 Datensätzen tun, müssen Sie möglicherweise nach dem Suchen und vor dem foreach ein .limit (300000) hinzufügen. Andernfalls kann das System abstürzen. Normalerweise beschränke ich Massenänderungen aus Sicherheitsgründen auf ca. 100.000. Wickeln Sie das Ganze in eine for-Schleife, basierend auf Anzahl und Limit.
Triunenature

6

Sie können das Aggregationsframework verwenden, um Ihr Problem zu beheben

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

Es ist zu beachten, dass Indizes aus oldCollection nicht in newCollection kopiert werden.


5

Ich weiß, dass diese Frage beantwortet wurde, aber ich persönlich würde @JasonMcCays nicht beantworten, da Cursor streamen und dies zu einer Endlosschleife führen kann, wenn die Sammlung noch verwendet wird. Stattdessen würde ich einen Schnappschuss () verwenden:

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

@bens Antwort ist auch eine gute und funktioniert gut für Hot-Backups von Sammlungen, nicht nur das, sondern Mongorestore muss nicht das gleiche Mongod teilen.


5

Dies mag nur ein Sonderfall sein, aber für eine Sammlung von 100.000 Dokumenten mit zwei zufälligen Zeichenfolgenfeldern (Länge 15 bis 20 Zeichen) ist die Verwendung einer dummen Mapreduce fast doppelt so schnell wie find-insert / copyTo:

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

5

Wenn Sie Pymongo verwenden, müssen Sie beide Datenbanken auf demselben Mongod haben. Ich habe Folgendes getan:


db = ursprüngliche Datenbank
db2 = Datenbank, in die kopiert werden soll

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

1
Dies würde viel Zeit in Anspruch nehmen, wenn die Datengröße sehr groß ist. Alternativ können Sie mass_insert
nishant

1
Ja, dies war nur eine schnelle und schmutzige Art, wie ich für mich arbeiten konnte. Meine Datenbank war nicht zu groß, aber auch nicht klein und dauerte nicht zu lange, aber ja, Sie haben Recht.
Vbhakta

2

Dies wird Ihr Problem nicht lösen, aber die Mongodb-Shell verfügt über eine copyToMethode, mit der eine Sammlung in eine andere in derselben Datenbank kopiert wird :

db.mycoll.copyTo('my_other_collection');

Es wird auch von BSON in JSON übersetzt, also mongodump/ mongorestoresind der beste Weg, wie andere gesagt haben.


Ausgezeichnet. Leider scheint die Mongo- Shell-Referenz diese Methode nicht zu erwähnen.
pgl

Ja, ich weiß, aber die MongoDB-Shell ist fantastisch, wenn Sie db.collname eingeben. [TAB] werden alle verfügbaren Methoden für das Sammlungsobjekt angezeigt. Dieser Tipp funktioniert für alle anderen Objekte.
Roberto

Das Problem ist der Mangel an Hilfe für diese Befehle! Es ist nützlich, den Code sehen zu können, indem Sie die Parens für einen Methodenaufruf weglassen.
pgl

2
Leider ist dieser Befehl seit Version 3.0 veraltet.
Harry

2

Wenn RAM kein Problem ist, insertManyist die Verwendung viel schneller als die forEachSchleife.

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

Für den Fall, dass einige Heroku-Benutzer hier stolpern und wie ich einige Daten aus der Staging-Datenbank in die Produktionsdatenbank kopieren möchten oder umgekehrt, gehen Sie wie folgt vor (Hinweis: Ich hoffe, es gibt keine Tippfehler, kann sie nicht überprüfen.) Ich werde versuchen, die Gültigkeit des Codes so schnell wie möglich zu bestätigen.

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

Sie können immer Robomongo verwenden. Ab Version 0.8.3 gibt es ein Tool, das dies tun kann, indem Sie mit der rechten Maustaste auf die Sammlung klicken und "Sammlung in Datenbank kopieren" auswählen.

Weitere Informationen finden Sie unter http://blog.robomongo.org/whats-new-in-robomongo-0-8-3/.

Diese Funktion wurde in 0.8.5 aufgrund ihres fehlerhaften Charakters entfernt, sodass Sie 0.8.3 oder 0.8.4 verwenden müssen, wenn Sie sie ausprobieren möchten.


6
Diese Funktion von Robomongo ist immer noch instabil. Es ist eine 50/50-Chance, dass es funktioniert.
23.

2
Dies scheint von 0.8.5
Carasel

0

In meinem Fall musste ich eine Teilmenge von Attributen aus der alten Sammlung in meiner neuen Sammlung verwenden. Also habe ich diese Attribute ausgewählt, während ich insert für die neue Sammlung aufgerufen habe.

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


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.