1

I'm trying to copy my db for testing purposes. I'm using the docs for that, but it still fails:

from pymongo import MongoClient

client = MongoClient(username='root', password='pass')
client.admin.command('copydb', fromdb='src', todb='dst')


OperationFailure: no such command: 'copydb', full error: {'ok': 0.0, 'errmsg': "no such command: 'copydb'", 'code': 59, 'codeName': 'CommandNotFound'}

When trying another command, from another section of the doc, it worked:

from pymongo import MongoClient

client = MongoClient(username='root', password='pass')
db = client.src
db.admin.command('copydb', fromdb='src', todb='dst')

The objects used here are different, but this is what the docs say... I still tried using the db object for the copydb - and failed again:

from pymongo import MongoClient

client = MongoClient(username='root', password='pass')
db = client.src
db.admin.command('buildinfo')

TypeError: 'Collection' object is not callable. If you meant to call the 'command' method on a 'Collection' object it is failing because no such method exists.

which means I use a bad object (makes sense, but I don't get how to make it work)

pymongo.version: '3.11.0'
mongodb version: 4.4.1 (running on docker)

CIsForCookies
  • 12,097
  • 11
  • 59
  • 124
  • 2
    Starting in version 4.2, MongoDB removes the copydb command. The deprecated db.copyDatabase(), which wraps the copydb command, can only be run against MongoDB 4.0 or earlier versions. https://docs.mongodb.com/manual/reference/method/db.copyDatabase/ – Anurag Wagh Oct 21 '20 at 11:57
  • @AnuragWagh Saw it now. I'm downgrading and checking (Works!), but surely there is a replacement method for newer versions, no? – CIsForCookies Oct 21 '20 at 11:58
  • 1
    An alternative would be to use `mongodump` and `mongorestore` commands https://docs.mongodb.com/database-tools/mongodump/#copy-clone-a-database But `pymongo` doesn't have an API which can `dump` and `restore` – Anurag Wagh Oct 21 '20 at 12:01
  • On the other hand, you can try `os`, `shutil` or `subprocess` to execute these shell commands https://stackoverflow.com/questions/89228/how-to-call-an-external-command – Anurag Wagh Oct 21 '20 at 12:02
  • @AnuragWagh I'm not sure this is possible... My host has no `mongod`, only `pymongo`. How could I access the `mongodump` from the host? – CIsForCookies Oct 21 '20 at 12:10

1 Answers1

0

Using the help from @AnuragWagh and this nice answer I managed to have my own script to handle dump & restore:

from bson.json_util import dumps, loads
import os
import pymongo


def backup_db(client, db_name, backup_dir):
    if not os.path.isdir(backup_dir):
        os.makedirs(backup_dir)

    database = client[db_name]
    collections = database.list_collection_names()

    for i, collection_name in enumerate(collections):
        col = getattr(database,collections[i])
        collection = col.find()
        jsonpath = collection_name + '.json'

        jsonpath = os.path.join(backup_dir, jsonpath)

        with open(jsonpath, 'wb') as jsonfile:
            jsonfile.write(dumps(collection).encode())


backup_dir = './bckp'
client = pymongo.MongoClient(host='localhost', username='root', password='pass')
src_db_name = 'Jenkins'
dst_db_name = 'Test'
backup_db(client, src_db_name, backup_dir)


for backup_collection in filter(lambda path: path.endswith('.json'), os.listdir(backup_dir)):
    collection_name = backup_collection.rstrip('.json')
    with open(os.path.join(backup_dir, backup_collection), 'rb') as backup_file:
        data = loads(backup_file.read())
        client[dst_db_name][collection_name].insert_many(data)

This is not the ideal solution. If you can, use mongodump & mongorestore. For my case (pymongo on a host without mongodb installed, this seems like the best solution)

CIsForCookies
  • 12,097
  • 11
  • 59
  • 124