Несколько SQL-запросов в Node с помощью oracledb - PullRequest
0 голосов
/ 20 ноября 2018

Я новичок в Node и у меня проблемы с чтением из Oracle.

У меня есть все базовые примеры, и я могу выдавать базовые запросы, обрабатывать результаты и т. Д.

Проблема в том, что мне нужно;

  1. Выполнить один запрос (Q1)
  2. Для каждого элемента в результатах Q1 мне нужно выполнить второй запрос (Q2)
  3. Мне нужно объединить результаты Q1 и Q2sв массив для возврата в качестве обещания

Я изо всех сил пытаюсь найти пример, где я могу выполнить # 2 - вызывать один и тот же запрос несколько раз для каждого элемента, возвращенного из Q1, используя то же соединение, которое былоиспользуется для Q1.

Мой код ниже - я сначала выполняю чтение, затем перебираю результаты, сохраняя объекты connection.execute, которые я затем запускаю через строку Promise.all - результат, который я просто выводил какЯ хочу, чтобы это работало, прежде чем я запишу логику для объединения результатов Q1 и Q2.

Когда я запускаю это через mocha, результаты не содержат никаких данных - я вижу заголовки столбцов, но нетданные.

Так чего мне здесь не хватает?

// placeholder for the connection
let conn;

// return case list array
var caseList = [];
var queryList = [];

return new Promise((resolve, reject) => {

    // retrieve connection
    oracledb.getConnection({
            user: dbconfig.user,
            password: dbconfig.password,
            connectString: dbconfig.connectString
        }) // the connection is returned as a promise
        .then(connection => {

            console.log('Connected to the DB!');

            // assign connection
            conn = connection;

            // execute statement
            return connection.execute(
                `select caseid, casereference, startdate from caseheader inner join orgobjectlink on caseheader.ownerorgobjectlinkid = orgobjectlink.orgobjectlinkid where orgobjectlink.username = :username`,
                [params.username], {
                    outFormat: oracledb.OBJECT // set the output format to be object
                }
            );
        })
        .then(result => {

            // iterate around rows
            result.rows.forEach(row => {

                var caseObj = {
                    caseID: row.CASEID,
                    reference: row.CASEREFERENCE,
                    dateAssigned: moment(row.STARTDATE).format('YYYY-MM-DD'),
                    username: params.username,
                }
                caseList.push(caseObj);

                console.log(caseObj.caseID)
                queryList.push(conn.execute(`select concernroleid, concernrolename from concernrole inner join caseparticipantrole on concernrole.concernroleid = caseparticipantrole.participantroleid where caseparticipantrole.caseid = :caseID and (caseparticipantrole.typecode = 'PRI' or caseparticipantrole.typecode = 'MEM')`,
                    [caseObj.caseID], {
                        outFormat: oracledb.OBJECT
                    }));

            });

            // build up queries
            return Promise.all(queryList).then(results => {
                console.log(results);

                Promise.resolve(results);
            }, err => {
                console.log(err);
            });
        }).then({
            if(conn){
                console.log("Closing DB connection");
                conn.close();

            }
        }).catch(err => {
            console.log('Error', err);
        });

});

Ответы [ 2 ]

0 голосов
/ 23 ноября 2018

Promise.all не будет работать для вас, так как вы хотите использовать одно соединение, и, как упоминалось ранее, соединение в любом случае будет выполнять только одно действие за раз.Чтобы решить эту проблему с помощью обещаний, вам нужно создать и развернуть цепочку обещаний.Я могу показать вам пример, но это противно - возможно, лучше просто забыть, что я упомянул это.

Лучшим вариантом было бы перейти в простой цикл for с помощью async / await.Я могу показать вам пример этого тоже, но опять же, я думаю, что это неправильный шаг.Мы называем эту строку выборкой строки (иначе медленно за медленным).

Вероятно, лучшим решением для вас будет взять результаты первого запроса и создать массив.Затем выполните второй запрос, используя одну из этих опций для обработки массива.https://oracle.github.io/node-oracledb/doc/api.html#sqlwherein

Вам нужно будет включить столбец caseid в предложение select и, возможно, даже упорядочить по этому столбцу, чтобы пост-обработка набора результатов была упрощена в Node.js.

Это решение может значительно улучшить производительность и использование ресурсов, но оно должно быть сбалансировано с количеством имеющихся у вас данных, ресурсами и т. Д. Я мог бы также показать вам пример этого, но это займет немногои я бы хотел получить от вас дополнительную информацию, чтобы убедиться, что мы на правильном пути.

0 голосов
/ 21 ноября 2018

Одной из проблем является то, что функция Promise.all().then... ничего не возвращает (и не требует дополнительных resolve()).Способ отсортировать это - создать небольшие тестируемые функции с обещанием возврата, и проверить их по отдельности .

Начните с простого, напишите тест mocha для подключения к базе данных ...

function connect() {
    return oracledb.getConnection({
        user: dbconfig.user,
        password: dbconfig.password,
        connectString: dbconfig.connectString
    });
}

Вот тот, который может запустить команду на БД.Проверьте это с помощью простого запроса, который, как вы знаете, вернет некоторые результаты.

function executeCmd(connection, cmd, params) {
    return connection.execute(cmd, params, { outFormat: oracledb.OBJECT });
}

Только с этими двумя (и еще одним) мы можем наметить простую функцию, которая выполняет свою работу: подключиться к базе данных, запуститьвыберите, обработайте каждый результат асинхронно, затем отключите.

function connectAndQuery(username) {
    let connection;
    return connect().then(result => {
        connection = result;
        let cmd = `select caseid, casereference, startdate from caseheader inner join orgobjectlink on caseheader.ownerorgobjectlinkid = orgobjectlink.orgobjectlinkid where orgobjectlink.username = :username`;
        return executeCmd(connection, cmd, [username]);
    }).then(result => {
        let promises = result.rows.map(row => processCaseRow(connection, row, username));
        return Promise.all(promises);
    }).then(result => {
        // result should be an array of caseObj's 
        return connection.close().then(() => result);
    });
}

Последнее, что нужно создать и протестировать, это функция, возвращающая обещание, которая обрабатывает строку из главной функции, описанной выше.

У меня былочтобы взять на себя некоторую свободу, но я думаю, что цель - учитывая строку, представляющую «case» - создать объект case, включая коллекцию «заинтересованных ролей», которые могут быть запрошены с помощью caseID.(эта последняя часть была моей идеей, но вы можете создать отдельную коллекцию, если хотите)

// return a promise that resolves to an object with the following properties...
// caseID, reference, dateAssigned, username, concernedRoles
// get concernedRoles by querying the db
function processCaseRow(connection, row, username) {
    var caseObj = {
        caseID: row.CASEID,
        reference: row.CASEREFERENCE,
        dateAssigned: moment(row.STARTDATE).format('YYYY-MM-DD'),
        username: username
    }
    let cmd = `select concernroleid, concernrolename from concernrole inner join caseparticipantrole on concernrole.concernroleid = caseparticipantrole.participantroleid where caseparticipantrole.caseid = :caseID and (caseparticipantrole.typecode = 'PRI' or caseparticipantrole.typecode = 'MEM')`;
    return executeCmd(connection, cmd, row.CASEID).then(result => {
        caseObj.concernedRole = result
        return caseObj
    })
}
...