#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, а не просто запускать их