使用oracledb在Node中进行大量SQL查询

时间:2018-11-20 19:52:56

标签: node.js promise es6-promise oracledb oracledb-npm

我是Node的新手,在从Oracle中读取时遇到问题。

我已经设置了所有基本示例,可以发出基本查询,并处理结果等。

我遇到的问题是我需要;

  1. 执行一个查询(Q1)
  2. 对于第一季度结果中的每个项目,我需要执行第二个查询(Q2)
  3. 我需要将Q1和Q2的结果合并到一个数组中以作为承诺返回

我正在努力寻找一个示例,我可以执行#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 :(得分:0)

一个问题是Promise.all().then...函数不返回任何内容(并且不需要附加的resolve())。进行排序的方法是构建小的,可测试的,承诺返回的函数,并分别进行测试

从简单开始,编写摩卡测试以连接到数据库...

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);
    });
}

构建和测试的最后一件事是一个返回承诺的函数,该函数处理上面主要函数中的一行。

我不得不对此采取一些自由,但是我认为目标是-给定一个代表“案例”的行,建立一个案例对象,包括可以通过caseID查询的“ concernedRoles”的集合。 (最后一点是我的想法,但您可以根据需要构建一个单独的集合)

// 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
    })
}

答案 1 :(得分:0)

Promise.all不适用于您,因为您要使用单个连接,并且如前所述,连接一次只能一次执行一项操作。要使用诺言解决此问题,您必须建立并展开诺言链。我可以向您展示一个示例,但这很讨厌-最好忘了我提到的示例。

更好的选择是使用async / await进入简单的for循环。我也可以向您展示这个例子,但是再次,我认为这是错误的举动。我们将这一行称为逐行提取(也称为慢速慢速)。

可能最适合您的解决方案是从第一个查询中获取结果并建立一个数组。然后使用这些选项之一执行第二个查询以处理数组。 https://oracle.github.io/node-oracledb/doc/api.html#sqlwherein

您需要将caseid列包括在select子句中,甚至可能按该列排序,以便在Node.js中简化结果集的后处理。

此解决方案有可能极大地提高性能和资源利用率,但是必须与您拥有的数据量,资源等保持平衡。我可能也可以向您展示一个示例,但这需要再花一点时间,我想从您那里获得更多信息,以确保我们走在正确的道路上。