Миграция SQL в MongoDB с использованием скрипта nodejs

#javascript #node.js #mongodb

Вопрос:

Я новичок в nodejs и в настоящее время выполняю миграцию sql в mongodb. Я создал скрипт для загрузки данных в mongodb из sql-запросов. Я создал скрипт с образцом кода из Google, и он работает. Но я столкнулся с проблемой ниже и нуждаюсь в обходном пути для этого.

У меня есть массив запросов sql, и мне не нужно запускать эти запросы, если в каком-либо из запросов есть какие-либо проблемы с синтаксисом или какие-либо ошибки в результате запроса. (Скажем, если у второго запроса проблема с синтаксисом, то нет необходимости загружать данные первого запроса в mongo, в настоящее время его загрузка в моем случае). В принципе, если в каком-либо запросе есть какие-либо проблемы, то нет необходимости загружать результат в коллекцию mongo. А также, если возникнут какие-либо проблемы со стороны монго, не нужно совершать транзакции.

Я использовал транзакции mongo здесь, чтобы откатить данные, если возникнут какие-либо ошибки. пожалуйста, найдите приведенный ниже код, и любая помощь будет очень признательна.Учетные данные sql и mongo являются только фиктивными данными.

код конфигурационного файла

   var mongoCollection = 'collectionName';
  exports.mongoCollection = mongoCollection;

var queryList = [
'sample query one',
'sample query two ' 
];
exports.queryList = queryList;
 

основной код скрипта

   var MongoClient = require('mongodb').MongoClient;
  var sql = require('mysql');

  const config = require('./assets/config');

var sqlConfig = {
user: 'username',
password: 'password',
server: 'servername',
database: 'databasename',
port: 'portname',
multipleStatements: true
};

async function transaction() {
  const mongodbUrl = 'mongourl';
   const client = await MongoClient.connect(mongodbUrl, {useNewUrlParser: true}, {useUnifiedTopology: 
true});
 const db = client.db();

config.queryList.forEach(query => {
    new sql.ConnectionPool(sqlConfig).connect().then(pool => {
        return pool.request().query(query)
    }).then(result => {
        (async()=>{
            const session = client.startSession();
            session.startSession({
                readConcers: {level: 'snapshot'},
                writeConcern: {w: 'majority'}
            });
            try {
                const collection = client.db('mongodbName').collection(config.mongoCollection);
                await collection.insertMany(result.recordset, {session});
                await session.commitTransaction();
                session.emdSession();
                console.log('transaction completed');
            }catch(error){
                await session.abortTransaction();
                session.endSession();
                console.log('transaction aborted');
                throw error;
            }
        });
        sql.close();
    }).catch(error => {
        sql.close();
        throw error;
    })
});
};

transaction();
 

Комментарии:

1. Просьба любезно обновить код, если я допустил какие-либо ошибки

Ответ №1:

В зависимости от объема данных вы можете рассмотреть возможность разбиения процесса на две части

  • Получите данные из MySQL
  • Если ошибок нет, загрузите в Mongo

Это избавило бы вас от необходимости откатывать записи монго

Вы также можете воспользоваться размером пула mongo по умолчанию (5) и использовать пул также на стороне MySQL. В настоящее время этот код создает пул для каждого выбора, что не является оптимальным

 config.queryList.forEach(query => {
    new sql.ConnectionPool(sqlConfig).connect().then(pool => {//<-New pool per query?
        return pool.request().query(query)
    })
})
 

Вместо этого вы можете настроить пул один раз в соответствии с документацией MySQL

Похоже, что у этого драйвера есть только api обратного вызова, но вы можете пообещать выполнить запрос, чтобы упростить работу с ним.

Поэтому, чтобы собрать все это воедино, вы могли бы попробовать что-то вроде этого (это не рабочий/проверенный код, просто предложение).

 var MongoClient = require('mongodb').MongoClient;
var sql = require('mysql');

const config = require('./assets/config');

var pool  = sql.createPool({
  connectionLimit : 5,
  host            : 'servername',
  user            : 'username',
  password        : 'password',
  database        : 'databasename'
});

async function transaction() {
  try{
    const mongodbUrl = 'mongourl';
    const client = await MongoClient.connect(mongodbUrl, {useNewUrlParser: true}, {useUnifiedTopology: true});
    const db = client.db();
    const collection = client.db('mongodbName').collection(config.mongoCollection);

    //Map your query list to an array of runSql promises
    //this will complete when all queries return, and jump to the catch if any fail
    let results = await Promise.all(config.queryList.map(runSql))
    
    //Map the results to an array of mongo inserts
    let inserts = await Promise.all(results.map(r=>collection.insertMany(r.recordset)))
    
    //Close all connections
    pool.end((err)=>err?console.err(err):console.log('MySQL Closed'))
    client.close((err)=>err?console.err(err):console.log('MongoDB Closed'))
  }
  catch(err){
    console.error(err)
  }
};

transaction();

function runSql(queryStr){
    return new Promise((resolve, reject)=>{
        pool.query(queryStr, function (error, results, fields){
            error?reject(error):resolve(results)
        })  
    })
}
 

Если объем данных вызывает беспокойство, вы можете захотеть посмотреть на получение потоков из вашего MySQL, а не просто запускать их