描述:

        migrate-mongo是一个js模块,通过migrate-mongo可以实现远程操作mongodb数据库。其中执行脚本的版本控制是通过配置文件进行远程MongoDB数据库连接配置,执行时在远程数据库下创建一个默认changelog集合,将执行文件记录存储下来。

mongodb脚本 graphLookup mongo执行脚本_mongodb

 

环境准备

服务端:

  • MongoDB副本集 - 为migrate-mongo提供MongoDB数据库支持,【副本集】提供migrate-mongo事务支持

客户端:

  • node环境 - 为migrate-mongo提供执行环境

基本用法

这里粗略写了一下,具体可以见最后详情链接

  • 初始化新项目
# 创建工作目录,并在目录下执行初始化
$ mkdir albums-migrations
$ cd albums-migrations
$ migrate-mongo init

上面的初始化命令做了两件事:

  1. 创建了一个migrate-mongo-config.js文件 (该文件用于连接MongoDB数据库相关配置)
  2. 创建了一个migrations文件夹 (该文件夹用于存储执行脚本文件)
  • 链接配置及配置信息加密

migrate-mongo-config.js文件配置详情

migrate-mongo-config.js文件为配置远程mongodb数据库的连接配置文件。编辑migrate-mongo-config.js文件,确保urldatabaseName正确配置。

// 在这个文件中,您可以配置migrate-mongo

module.exports = {
  mongodb: {
    // MongoDB地址: 
    url: "mongodb://localhost:27017",

    // MongoDB数据库名称:
    databaseName: "YOURDATABASENAME",

    options: {
      useNewUrlParser: true // 连接时删除弃用警告
      //   connectTimeoutMS: 3600000, // 将连接超时时间设置为1小时
      //   socketTimeoutMS: 3600000, // 将套接字超时时间增加到1小时
    }
  },

  // 迁移目录可以是相对路径或绝对路径。仅在确实需要时编辑此内容。
  migrationsDir: "migrations",

  // 存储应用的更改的mongodb集合。仅在确实需要时编辑此内容。
  changelogCollectionName: "changelog",

  // 在迁移目录中创建迁移和搜索的文件扩展名
  migrationFileExtension: ".js",

  // 启用算法以创建文件内容的校验和,并在比较中使用该校验和来确定
  // useFileHash设置为false,migrations下执行文件被执行后,变更文件内容执行将不发生变化。为true,执行将更新
  useFileHash: false
};

配置信息加密实现

实际使用过程中我们一般会对敏感属性不能直接暴露出来,需要做加密处理。migrate-mongo目前自身未提供对配置文件加密功能。实现方案: 通过crypto-js依赖实现对url配置信息进行加密,重写migrate-mongo,在加载属性时进行解密。

加密url示例

首先下载用于加密的依赖:npm install crypto-js

然后创建一个js文件,填充以下内容:

var CryptoJS = require("crypto-js");
// Encrypt
var ciphertext = CryptoJS.AES.encrypt("mongodb://user:passwd@101.32.14.131:8080/mongo", 'secret key 123').toString();
console.log(ciphertext);

执行node xx.js即可在屏幕上获取到输出的加密内容

mongodb脚本 graphLookup mongo执行脚本_数据库_02

 

重写migrate-mongo属性加载部分代码 database.js:

$ vi /usr/local/lib/node_modules/migrate-mongo/lib/env/database.js

const { MongoClient } = require("mongodb");
const _ = require("lodash");
const config = require("./config");
var CryptoJS = require("crypto-js");        // crypto-js依赖引入

module.exports = {
  async connect() {
    const configContent = await config.read();
    //const url = _.get(configContent, "mongodb.url");
    let url = _.get(configContent, "mongodb.url");             // 对加密url进行解密处理
    var bytes  = CryptoJS.AES.decrypt(url, 'secret key 123');  // 对加密url进行解密处理
    url = bytes.toString(CryptoJS.enc.Utf8);                   // 对加密url进行解密处理
    const databaseName = _.get(configContent, "mongodb.databaseName");
    const options = _.get(configContent, "mongodb.options");
  • 执行脚本创建及编排

执行脚本创建

$ cd albums-migrations
$ migrate-mongo create [description]

For example:

$ migrate-mongo create blacklist_the_beatles

创建: migrations/20221010111912-blacklist_the_beatles.js

执行脚本编辑

脚本详情

up部分写入执行脚本,down部分写入回退脚本


module.exports = { async up(db, client) {
  // TODO write your migration here.
  // See https://github.com/seppevs/migrate-mongo/#creating-a-new-migration-script
  // Example:
  // return db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: true}});
  // await db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: true}});
 },

 async down(db, client) {
  // TODO write the statements to rollback your migration (if possible)
  // Example:
  // await db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: false}});
 }
};


  • 执行、回退操作

执行

执行migrations目录下所有未被执行的.js脚本文件

$ migrate-mongo up

回退

每次回退只会向上回退一次记录(最近一个.js脚本文件)

$ migrate-mongo down

  • 事务实现

官方文档里面没有加session,执行发现不能实现事务提交。看了官方文档,发现加session,试了一下成了。

module.exports = {
  async up(db, client) {
    const session = client.startSession();
    try {
        await session.withTransaction(async () => {
            await db.collection('mongo').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: true}}, { session });
            await db.collection('mongo').updateOne1({artist: 'The Doors'}, {$set: {stars: 5}}, { session });
        });
    } finally {
      await session.endSession();
    }
  },

  async down(db, client) {
    const session = client.startSession();
    try {
        await session.withTransaction(async () => {
            await db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: false}}, { session });
            await db.collection('albums').updateOne({artist: 'The Doors'}, {$set: {stars: 0}}, { session });
        });
    } finally {
      await session.endSession();
    }
  },
};