Як скопіювати колекцію з однієї бази даних в іншу в MongoDB


221

Чи є простий спосіб це зробити?


40
Прийнята відповідь була, мабуть, найкращим методом ще в 2012 році, але тепер db.cloneCollection () часто є кращим рішенням. Тут є кілька останніх відповідей, які посилаються на це, тому якщо ви прийшли сюди з Google (як я), подивіться на всі відповіді!
Келвін

4
Не забудьте прочитати й інші відповіді, хоча переконайтеся, що вони відповідають вашим потребам, а не лише @kelvin 'у його / її ситуації
PW Kad

Відповіді:


206

Наразі в MongoDB немає команди, яка б це зробила. Зверніть увагу на квиток JIRA з відповідним запитом на функції .

Ви можете зробити щось на кшталт:

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

Зверніть увагу, що для цього для двох баз даних потрібно мати спільний доступ до одного і того ж мондору, щоб це працювало.

Крім цього, ви можете виконати збір колекції з однієї бази даних, а потім виконати моніторинг колекції в іншій базі даних.


13
Зауважте, що якщо ви копіюєте в оболонку JS, документи BSON під час процесу декодуються до JSON, тому деякі документи можуть мати зміни типу. mongodump / mongorestore, як правило, кращий підхід.
Стенні

1
Домовились. Це було просто веселіше пропозиція пограти з оболонкою. Плюс до цього, індекси не принесуть. Якби я робив це, я би робив mongodump / mongorestore кожного разу.
Джейсон Маккей

2
Дякую. Зверніть увагу, що у вас є помилка друку в коді, не закриваючи функцію getSiblingDB. Ось виправлений код: db. <collection_name> .find (). ForEach (функція (d) {db.getSiblingDB ('<new_database>') ['<collection_name>'] .insert (d);});
Флавіу

1
це добре працювало для скидання тестового mongodb із золотої копії між тестовими прогонами. замість жорсткого кодування назв колекції ви можете зробити цикл для всіх назв колекції, які ви хочете скопіювати, за допомогою db.getCollection (name) .find (). forEach і надайте функцію, яка має db.getSiblingDB ("otherdb"). getCollection (назва) .insert (d).
simbo1905

2
це ефективно для величезних розмірів колекцій?
Халил Авада

284

Найкращий спосіб - це зробити мондомпа, а потім Монгоресторе.

Ви можете вибрати колекцію за допомогою:

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 базами даних, вам просто потрібно передати автентичний параметр
Ben

2
Це набагато швидше, ніж знайти / forEach / вставити, в моєму випадку 2 хвилини проти 2 години
Юрай Пауло

Введіть ім'я користувача для бази даних з --username, але не - пароль, щоб отримати підказку про пароль. Краще не ставити пароль у своєму командному рядку (закінчуючи збереженням його у .bash_history чи подібному)
Chanoch

Minor: Я знайшов файл в підкаталозі з ім'ям , some_database так це працює для мене: mongorestore -d -c some_other_db some_or_other_collection дамп / 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
Thx чудово працює! Просто потрібно закриває апостроф'db1.source_collection'
andrrs

4
Замість "використовувати адміністратора", а потім "db.runCommand (..." Ви можете виконати лише одну команду, "db.adminCommand (..."
Хамід

25

Я б зловживав функцією підключення в mongo cli mongo doc . так що це означає, що ви можете запустити одне або більше з'єднань. якщо ви хочете скопіювати колекцію клієнтів з тесту на test2 на одному сервері. спочатку ви запускаєте панцир монго

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

зробіть звичайну знахідку та скопіюйте перші 20 записів на тест2.

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
Коли я коментував пропозицію Джейсона, майте на увазі, що якщо ви копіюєте в оболонку JS, документи BSON під час процесу декодуються до JSON, тому деякі документи можуть мати зміни типу. Існують аналогічні міркування щодо обмежень eval, і це буде більш повільним процесом копіювання значної кількості даних між базами даних (особливо на одному сервері). Тож mongodump / mongorestore FTW :).
Стенні

19

Якщо між двома віддаленими монгодними екземплярами, використовуйте

{ 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>", з: "<ім'я імені>", запит: {<query>}})
Даніель де Зван

Як це можна використовувати для поступових оновлень від одного віддаленого монго до іншого?
нишант

У мене дані користувачів додаються до одного екземпляра монго протягом дня. У кінці дня мені потрібно перенести щойно додані рядки до іншого екземпляра монго. Як цього можна досягти?
нішант

@NishantKumar спробуйте встановити запит: {} цей код: $ where: function () {сьогодні = нова дата (); // сьогодні.setHours (0,0,0,0); return (this._id.getTimestamp ()> = сьогодні). Дивіться stackoverflow.com/questions/42456375/… .
es одеколон

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 sec vs 3 sec)


це набагато краще, ефективніше, забиває менше db, працює для будь-якого розміру набору даних.
Джеремі

Якщо ви робите це з більш ніж 300 000 записів, вам може знадобитися додати .limit (300000) після знаходження та перед передбаченням. В іншому випадку система може заблокуватися. Зазвичай я обмежую групові зміни приблизно до 100 тис. Для безпеки. Загортання всієї речі в цикл for на основі підрахунку та обмеження.
триєдиність

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 майже вдвічі швидше, ніж find-insert / copyTo:

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

5

Використовуючи pymongo, вам потрібно мати обидві бази даних в одному монгоді, я зробив наступне:


db = оригінальна база даних
db2 = база даних, яку потрібно скопіювати

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

1
це займе багато часу, якщо розмір даних величезний. Крім того, ви можете використовувати bulk_insert
nishant

1
Так, це був просто швидкий і брудний спосіб, який я знайшов працювати для мене, моя база даних була не надто великою, але не малою і не зайняла занадто багато часу, але так, ви правильно.
вбхакта

2

Це не вирішить вашу проблему, але оболонка mongodb має copyToметод, який копіює колекцію в іншу в тій самій базі даних :

db.mycoll.copyTo('my_other_collection');

Це також перекладається з BSON в JSON, тому mongodump/ mongorestoreяк це найкращий шлях, як казали інші.


Відмінно. На жаль, посилання на оболонку Монго, схоже, не згадує цей метод.
pgl

Так, я знаю, але оболонка MongoDB є приголомшливою, якщо ви введете db.collname. [TAB] ви побачите всі доступні методи об’єкта колекції. ця порада працює для всіх інших об'єктів.
Роберто

Проблема полягає у відсутності допомоги для цих команд! Корисно мати можливість бачити код, однак, опустивши паролі до виклику методу.
pgl

2
На жаль, ця команда застаріла з версії 3.0.
Гаррі

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())

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
Ця особливість Робомонго досі нестабільна. Це 50/50 шанс змусити його працювати.
thedp

2
Здається, це було знято з
0,8,5

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/


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.