Как скопировать коллекцию из одной базы данных в другую в MongoDB

189

Есть ли простой способ сделать это?

  • 33
    Принятый ответ, возможно, был лучшим методом еще в 2012 году, но теперь db.cloneCollection () часто является лучшим решением. Здесь есть несколько недавних ответов, которые относятся к этому, поэтому, если вы пришли сюда из Google (как я), взгляните на все ответы!
  • 3
    Обязательно прочитайте и другие ответы, хотя, чтобы убедиться, что они соответствуют вашим потребностям, а не только @kelvin в его / ее ситуации
Теги:

18 ответов

178
Лучший ответ

В настоящий момент в 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, как правило, лучший подход.
  • 1
    Согласовано. Это было просто забавное предложение поиграться с раковиной. Плюс, это не принесло бы индексы. Если бы я делал это, я бы делал mongodump / mongorestore каждый раз.
Показать ещё 6 комментариев
242

Лучший способ - сделать mongodump, а затем mongorestore.

Вы можете выбрать коллекцию с помощью:

mongodump -d some_database -c some_collection

[Необязательно, zip дамп (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.

  • 2
    Отлично ... :) .. сэкономил мое время .. спасибо ..
  • 0
    Кажется, что mongodump не работает, если у вас есть защищенный паролем экземпляр mongo (и вы должны!)
Показать ещё 4 комментария
78

На самом деле существует команда переместить коллекцию из одной базы данных в другую. Он просто не называется "переместить" или "скопировать".

Чтобы скопировать коллекцию, вы можете клонировать ее на том же 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'
  • 1
    @ Anuj, это мой любимый подход!
Показать ещё 2 комментария
21

Я бы злоупотреблял функцией connect в mongo cli mongo doc. так что вы можете запустить одно или несколько соединений. если вы хотите скопировать коллекцию клиентов с теста на test2 на том же сервере. сначала вы запускаете оболочку mongo

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 или hostname, чтобы подключиться к удаленному серверу. Я использую это для копирования тестовых данных в тестовую базу данных для тестирования.

  • 4
    Как я прокомментировал предложение Джейсона, имейте в виду, что если вы копируете в оболочку JS, документы BSON декодируются в JSON во время процесса, поэтому некоторые документы могут подвергаться изменениям типа. Есть ограничения, аналогичные ограничениям eval, и это будет более медленный процесс копирования значительных объемов данных между базами данных (особенно на одном сервере). Итак, монгодумп / монгорестор FTW :).
18

Если между двумя удаленными экземплярами mongod используйте

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

См. http://docs.mongodb.org/manual/reference/command/cloneCollection/

  • 0
    copyIndexes опции copyIndexes фактически не соблюдается. Индексы всегда копируются. Смотри SERVER-11418
  • 5
    Оберните это в db.runCommand (), т.е. db.runCommand ({cloneCollection: "<collection>", from: "<hostname>", query: {<query>}})
Показать ещё 4 комментария
17

Я обычно делал:

use sourcedatabase;
var docs=db.sourcetable.find();
use targetdatabase;
docs.forEach(function(doc) { db.targettable.insert(doc); });
  • 1
    Это так здорово и просто
5

Вы можете использовать инфраструктуру агрегации для решения проблемы

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

Следует отметить, что индексы из oldCollection не будут скопированы в newCollection.

5

Это может быть только особый случай, но для коллекции из 100k документов с двумя случайными строковыми полями (длина - 15-20 символов), использование немого mapreduce почти в два раза быстрее, чем find-insert/copyTo:

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

Я знаю, что на этот вопрос был дан ответ, однако я лично не буду отвечать @JasonMcCays из-за того, что поток курсоров и это может вызвать бесконечный цикл курсора, если коллекция все еще используется. Вместо этого я использовал бы снимок():

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

Ответ на

@bens также хорош и хорошо работает для горячих резервных копий коллекций не только, но и mongorestore не нужно использовать один и тот же mongod.

4

Используя pymongo, вам нужно иметь обе базы данных на одном и том же mongod, я сделал следующее:


db= исходная база данных
  db2= база данных, которая будет скопирована в

cursor = db["<collection to copy from>"].find()
for data in cursor:
    db2["<new collection>"].insert(data)
  • 1
    это займет много времени, если размер данных огромен. В качестве альтернативы вы можете использовать bulk_insert
  • 1
    Да, это был простой и грязный способ, который я нашел для себя, моя база данных была не слишком большой, но и не маленькой, и не заняла слишком много времени, но да, вы правы.
2

для коллекций большого размера вы можете использовать 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 секунд)

  • 0
    это намного лучше, эффективнее, с меньшими затратами, работает для любого размера набора данных.
  • 0
    Если вы делаете это с более чем 300 тыс. Записей, вам может потребоваться добавить .limit (300000) после поиска и перед foreach. В противном случае система может заблокироваться. Я обычно ограничиваю массовые изменения до 100 тыс. Для безопасности. Оборачивание всего этого в цикл for на основе количества и предела.
2

Если оперативная память не является проблемой, использование 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())
2

Это не решит вашу проблему, но оболочка mongodb имеет copyTo метод, который копирует коллекцию в другую в той же базе данных

db.mycoll.copyTo('my_other_collection');

Он также переводится с BSON на JSON, поэтому mongodump/mongorestore - лучший способ пойти, как говорили другие.

  • 0
    Отлично. К сожалению, ссылка на оболочку Mongo, похоже, не упоминает этот метод.
  • 0
    Да, я знаю, но оболочка MongoDB великолепна, если вы введете db.collname. [TAB] вы увидите все доступные методы для объекта коллекции. этот совет работает для всех других объектов.
Показать ещё 2 комментария
1

В случае, если некоторые пользователи героику спотыкаются здесь и, как и я, я хочу скопировать некоторые данные из промежуточной базы данных в производственную базу данных или наоборот здесь, как вы делаете это очень удобно (NB, я надеюсь, что там нет опечаток, не могу проверить это atm., я попробую подтвердить правильность кода как можно скорее):

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. Начиная с версии 0.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 шанс заставить его работать.
  • 0
    Да. Это работает в RoboMongo
Показать ещё 1 комментарий
0

используйте "Studio3T for MongoDB" с инструментами "Экспорт" и "Импорт", щелкнув ссылку на базу данных, коллекцию или ссылку для загрузки конкретной коллекции: https://studio3t.com/download/

0

В моем случае мне пришлось использовать подмножество атрибутов из старой коллекции в моей новой коллекции. Поэтому я решил выбрать эти атрибуты, вызывая вставку в новую коллекцию.

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

Это можно сделать с помощью метода Mongo db.copyDatabase:

db.copyDatabase(fromdb, todb, fromhost, username, password)

Ссылка: http://docs.mongodb.org/manual/reference/method/db.copyDatabase/

  • 10
    ОП хотел скопировать коллекцию, а не всю БД.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню