db-migrate / mongodb

mongodb driver for db-migrate

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Basic example code usage in readme

jirikrepl opened this issue · comments

Hi I am struggling to get this package working. Seems to me that I have connection to mongo db setup properly, because I could list my collections names from calling db._getCollectionNames

but I am not able to figure out how to get collection, so I can perform update on collection:

exports.up = function (db) {
    // how to use db to get to collection?
    // this won't work
    db.collection('Profile').update({},
        { $set: { "termsOfServiceUpdated": true } },
        {
            upsert: false,
            multi: true
        });
};

thank you very much


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

This is a migration library, not just a wrapper for the driver below. So you first need to access the driver should you want to perform operations not, yet, directly supported by the driver or the framework.

In case of mongodb this is getDbInstance merged from this PR over here #21

Hi, sorry new to this but trying to use getDbInstance, would this be a case of just doing

exports.up = function(db, callback) {
    db.getDbInstance().getCollection(....)....
}

Thanks in advance.

Kind regards
Sidharth

Hi, sorry new to this but trying to use getDbInstance, would this be a case of just doing

exports.up = function(db, callback) {
    db.getDbInstance().getCollection(....)....
}

Thanks in advance.

Kind regards
Sidharth

@sidharthnayyar were you able to get db.getDbInstance() working? When I try to run it I get [ERROR] TypeError: db.getDbInstance is not a function. I confirmed I have db-migrate-mongodb@1.4.0 too.

I also got db.getDbInstance is not a function. Stacktrace was from db-migrate, maybe the db object in exports.up and exports.down only has available functions from db-migrate (createCollection, dropCollection, addIndex etc.).

But debugging db, was able to get this working:

exports.up = function(db) {
  let mClient;
  return db.connection.connect(db.connectionString, { native_parser: true })
    .then((mClientInst) => {
      // mClientInst is an instance of MongoClient
      mClient = mClientInst;
      return mClient.collection('myCollection')...;
    })
    .then(() => mClient.close())
    .catch(() => mClient.close());
};

Migrations can be debugged with VS Code by adding the following to launch.json, then put a breakpoint in any up/down function:

"configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "DB Migrate Down",
      "program": "${workspaceFolder}/node_modules/.bin/db-migrate",
      "args": [
        "down"
      ]
    },
    {
      "type": "node",
      "request": "launch",
      "name": "DB Migrate Up",
      "program": "${workspaceFolder}/node_modules/.bin/db-migrate",
      "args": [
        "up"
      ]
    },
    ...
  ]
}

Thanks for sharing your trick to getting an instance of Mongo client, @danielabar. It seems like it would open 2 connections to the db though? Thanks also for the debugging tip, that is super useful!

Actually after I posted I found this on the web, so here's what I have for now:

const collections = [{
    name: 'users'
}];

exports.down = async (db) => {
    const dbDriver = await db._run('getDbInstance');
    collections.forEach(async (collection) => {
        const fileName = collection.dataFile || `${collection.name}.json`;
        const data = require(Path.join(__dirname, 'docs', fileName));

        await Promise.all(data.map((doc) => {
            return dbDriver.collection(collection.name).deleteOne({ _id: doc._id });
        }));
    });

    dbDriver.close();
};

I wonder if there's a better way than both of ours though -- it seems risky resorting to using undocumented methods that may change internally.

I see what you mean about connecting twice. Also good point about undocumented methods.

To project maintainers: Any thoughts on this - what's the recommended way to get access to mongo instance, given that getDBInstance method from PR #21 isn't working (or not sure on correct usage)?

commented

The problem is how the db-migrate reduce driver object to the interface db-migrate/lib/migrator.js:51-52

var Migrator = function (driver, migrationsDir, empty, intern) {
  this.driver = dbmUtil.reduceToInterface(driver, MigratorInterface);

Function reduceToInterface will remove all methods that fall outside the interface, but there is a simple solution - modify the extending object exported by adding empty method getDbInstance in db-migrate\lib\interface\migratorInterface.js module. It can be done by using db-migrate programable API (file db-migrate.js):

const MigratorInterface = require('db-migrate/lib/interface/migratorInterface');

const dummy = () => undefined;
MigratorInterface.extending.getDbInstance = dummy;

const DbMigrate = require('db-migrate');

const dbmigrate = DbMigrate.getInstance();
if (dbmigrate.registerAPIHook) {
  dbmigrate.registerAPIHook()
    .then(() => {
      dbmigrate.run();
    });
} else { dbmigrate.run(); }

Now node db-migrate should be called instead of node_modules/.bin/db-migrate and this way getDbInstance is available to use in migrations scripts.

commented

This will help people who are still looking for it:

exports.up = function(db) {
  return db._run("update", "collectionToUpdate", {
    query: { id: "1123" }, // What you need to find
    update: { title: "myNewTitle", desc: "It works" }, // What you need to change
    options: {}, // Options like e.g: upsert: false,
  });
};

Have a look here
There is also updateMany

please be aware _ methods are private and subject to change at any time without warning. they may completely change their behavior or suddenly disappear. you can use them, but be prepared that you might have to change your migrations or fixate a driver version.

commented

Is there any other way?

Hello, I've been using db-migrate with mysql and it's working fine.
Now I wanted to use db-migrate with mongodb and am having trouble implementing a migration.

The only documentation I found is here:
https://db-migrate.readthedocs.io/en/latest/API/NoSQL/
It would imply there is no officially supported way of updating or deleting records - or am I missing something?

Thanks for any answer - I'll try using @jugaltheshah suggested method for now.

commented

Not the official way but you can use the bellow code to remove a single entry:

exports.down = function(db, callback) {
  db._run("remove", "pages", { id: "5bb9e79df82c0151fc0cdab2" }, callback);
};

But the code has a bug with deleteMany at the moment so you can use @jugaltheshah method.

exports.down = async function(db) {
  // Remove them all. (bug in their method at the moment)
  const getDbInstance = await db._run("getDbInstance");
  getDbInstance.collection("pets").deleteMany({ type: "cat" }); // Removes all occurrence of that value.
  getDbInstance.close();
};

More details here: https://github.com/db-migrate/mongodb/blob/master/index.js#L337

thanks - I'm doing that and its working fine 👍