Cómo copiar una colección de una base de datos a otra en MongoDB


221

¿Hay una manera simple de hacer esto?


40
La respuesta aceptada fue posiblemente el mejor método en 2012, pero ahora db.cloneCollection () es a menudo una mejor solución. Aquí hay un par de respuestas más recientes que se refieren a esto, así que si viniste aquí desde Google (como lo hice yo), ¡mira todas las respuestas!
Kelvin

44
Asegúrese de leer también las otras respuestas para asegurarse de que se ajuste a sus necesidades, no solo de @kelvin en su situación
PW Kad

Respuestas:


206

Por el momento no hay un comando en MongoDB que haga esto. Tenga en cuenta el boleto JIRA con la solicitud de función relacionada .

Podrías hacer algo como:

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

Tenga en cuenta que con esto, las dos bases de datos tendrían que compartir el mismo mongod para que esto funcione.

Además de esto, puede hacer un mongodump de una colección de una base de datos y luego mongorestore la colección a la otra base de datos.


13
Tenga en cuenta que si copia en el shell JS, los documentos BSON se decodifican a JSON durante el proceso, por lo que algunos documentos pueden sufrir cambios de tipo. mongodump / mongorestore son generalmente el mejor enfoque.
Stennie

1
Convenido. Eso fue más que una sugerencia divertida para jugar con la concha. Además, no traería los índices. Si estuviera haciendo esto, haría el mongodump / mongorestore cada vez.
Jason McCay

2
Gracias. Tenga en cuenta que tiene un error tipográfico en el código, que no cierra la función getSiblingDB. Aquí está el código corregido: db. <collection_name> .find (). ForEach (function (d) {db.getSiblingDB ('<new_database>') ['<collection_name>'] .insert (d);});
Flaviu

1
Esto funcionó bien para restablecer un mongodb de prueba desde una copia dorada entre las ejecuciones de prueba. en lugar de codificar los nombres de las colecciones, puede hacer un bucle for sobre todos los nombres de las colecciones que desea copiar con db.getCollection (name) .find (). forEach y proporcionar una función que tenga db.getSiblingDB ("otherdb"). getCollection (nombre). inserción (d).
simbo1905

2
¿Es esto eficiente para colecciones de gran tamaño?
Khalil Awada

284

La mejor manera es hacer un mongodump y luego mongorestore.

Puede seleccionar la colección a través de:

mongodump -d some_database -c some_collection

[Opcionalmente, comprime el dump ( zip some_database.zip some_database/* -r) y scpen otro lugar]

Luego restaurarlo:

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

Los datos existentes en some_or_other_collectionse conservarán. De esa manera puede "agregar" una colección de una base de datos a otra.

Antes de la versión 2.4.3, también deberá volver a agregar sus índices después de copiar sus datos. A partir de 2.4.3, este proceso es automático y puede deshabilitarlo con --noIndexRestore.


Parece que mongodump no funciona si tiene una instancia de mongo protegida con contraseña (¡y debería hacerlo!)
Luciano Camilo

3
Funciona en bases de datos protegidas por PW, solo necesita pasar la autenticación en los parámetros
Ben

2
Esto es mucho más rápido que find / forEach / insert, en mi caso 2 minutos vs 2 horas
Juraj Paulo

Pase el nombre de usuario para la base de datos con --username pero no --password para obtener una solicitud de contraseña. Es mejor no poner la contraseña en su línea de comando (terminando guardándola en .bash_history o similar)
Chanoch

Menor: Encontré el archivo en una subcarpeta nombrada por some_database, así que esto funciona para mí: mongorestore -d some_other_db -c some_or_other_collection dump / some_database / some_collection.bson
Aviko

88

En realidad, no es un comando para mover una colección de una base de datos a otro. Simplemente no se llama "mover" o "copiar".

Para copiar una colección, puede clonarla en la misma base de datos y luego mover la copia.

Para clonar:

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

Para mover:

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

Las otras respuestas son mejores para copiar la colección, pero esto es especialmente útil si está buscando moverla.


3
¡Thx funciona muy bien! Solo necesita un apóstrofo de cierre'db1.source_collection'
llega el

44
En lugar de "usar admin" seguido de "db.runCommand (..." Puede hacer solo un comando, "db.adminCommand (..."
Hamid

25

Abusaría de la función de conexión en mongo cli mongo doc . eso significa que puede iniciar una o más conexiones. si desea copiar la colección de clientes de prueba a prueba2 en el mismo servidor. primero comienzas mongo shell

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

haga una búsqueda normal y copie los primeros 20 registros a test2.

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

o filtrar por algunos criterios

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

simplemente cambie el host local a IP o nombre de host para conectarse al servidor remoto. Lo uso para copiar datos de prueba a una base de datos de prueba para probar.


44
Como comenté sobre la sugerencia de Jason, tenga en cuenta que si copia en el shell JS, los documentos BSON se decodifican a JSON durante el proceso, por lo que algunos documentos pueden sufrir cambios de tipo. Existen consideraciones similares a las Limitaciones de eval y este va a ser un proceso más lento para copiar cantidades significativas de datos entre bases de datos (particularmente en el mismo servidor). Entonces mongodump / mongorestore FTW :).
Stennie

19

Si está entre dos instancias remotas de mongod, use

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

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


El copyIndexescampo de opción en realidad no se respeta. Los índices siempre se copian. Ver SERVER-11418
Gianfranco P.

66
Envuelva eso en db.runCommand () es decir, db.runCommand ({cloneCollection: "<collection>", de: "<hostname>", consulta: {<query>}})
Daniel de Zwaan

¿Cómo puede usarse esto para actualizaciones incrementales de un mongo remoto a otro?
nishant

Tengo datos de usuario que se agregan a una instancia de mongo durante todo el día. Al final del día, necesito transferir las filas recién agregadas a otra instancia de mongo. ¿Cómo se puede lograr esto?
nishant

@NishantKumar intenta establecer en la consulta: {} este código: $ where: function () {today = new Date (); // today.setHours (0,0,0,0); return (this._id.getTimestamp ()> = hoy). Ver stackoverflow.com/questions/42456375/… .
es colonia

18

Yo generalmente haría:

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

11

para colecciones de gran tamaño, puede usar Bulk.insert ()

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

Esto ahorrará mucho tiempo . En mi caso, estoy copiando la colección con 1219 documentos: iter vs Bulk (67 segundos frente a 3 segundos)


esto es mucho mejor, más eficiente, da menos db, funciona para cualquier tamaño de conjunto de datos.
Jeremie

Si está haciendo esto con más de 300k registros, es posible que deba agregar un límite. (300000) después del hallazgo y antes del foreach. De lo contrario, el sistema puede bloquearse. Por lo general, limito los cambios a granel a aproximadamente 100k por seguridad. Envolviendo todo en un bucle for basado en conteo y límite.
triunenature

6

Puede usar el marco de agregación para resolver su problema

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

Cabe señalar que los índices de oldCollection no se copiarán en newCollection.


5

Sé que esta pregunta ha sido respondida, sin embargo, personalmente no respondería @JasonMcCays debido al hecho de que los cursores fluyen y esto podría causar un bucle de cursor infinito si la colección todavía se está utilizando. En su lugar, usaría una instantánea ():

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

La respuesta de @bens también es buena y funciona bien para las copias de seguridad de colecciones, no solo eso, sino que mongorestore no necesita compartir el mismo mongod.


5

Esto podría ser solo un caso especial, pero para una colección de documentos de 100k con dos campos de cadena aleatorios (la longitud es de 15-20 caracteres), el uso de un mapa reducido es casi el doble de rápido que find-insert / copyTo:

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

5

Usando pymongo, necesitas tener ambas bases de datos en el mismo mongod, hice lo siguiente:


db = base de datos original
db2 = base de datos a copiar

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

1
esto llevaría mucho tiempo si el tamaño de los datos es enorme. Alternativamente, puede usar bulk_insert
nishant

1
Sí, esta fue una manera rápida y sucia que encontré que funcionaba para mí, mi base de datos no era demasiado grande, pero tampoco pequeña y no tardó demasiado, pero sí, está en lo correcto.
vbhakta

2

Esto no resolverá su problema, pero el shell mongodb tiene un copyTométodo que copia una colección en otra en la misma base de datos :

db.mycoll.copyTo('my_other_collection');

También se traduce de BSON a JSON, por lo que mongodump/ mongorestoreson la mejor manera de hacerlo, como han dicho otros.


Excelente. Lamentablemente, la referencia de shell Mongo no parece mencionar este método.
pgl

Sí, lo sé, pero el shell MongoDB es increíble, si escribe db.collname. [TAB] verá todos los métodos disponibles en el objeto de colección. Este consejo funciona para todos los demás objetos.
Roberto

¡El problema es la falta de ayuda para esos comandos! Es útil poder ver el código, aunque omitiendo a los padres en una llamada al método.
pgl

2
Lamentablemente, este comando ahora ha quedado en desuso desde la versión 3.0.
Harry

2

Si la RAM no es un problema, el uso insertManyes mucho más rápido que el forEachbucle.

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

En caso de que algunos usuarios de heroku tropiecen aquí y, como yo, quieran copiar algunos datos de la base de datos provisional a la base de datos de producción o viceversa, así es como lo hacen de manera muy conveniente (Nota: espero que no haya errores tipográficos allí, no puedo verificarlo en el cajero automático). Intentaré confirmar la validez del código lo antes posible):

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

Siempre puedes usar Robomongo. A partir de v0.8.3 hay una herramienta que puede hacer esto haciendo clic derecho en la colección y seleccionando "Copiar colección a la base de datos"

Para más detalles, consulte http://blog.robomongo.org/whats-new-in-robomongo-0-8-3/

Esta característica se eliminó en 0.8.5 debido a su naturaleza defectuosa, por lo que deberá usar 0.8.3 o 0.8.4 si desea probarla.


66
Esta característica de Robomongo todavía es inestable. Es una posibilidad de 50/50 para que funcione.
thedp

2
Esto parece haber sido eliminado de 0.8.5
Carasel

0

En mi caso, tuve que usar un subconjunto de atributos de la colección anterior en mi nueva colección. Así que terminé eligiendo esos atributos al llamar a insert en la nueva colección.

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


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.