Multple SQL queries in Node with oracledb












0














I'm new to Node and am having problems reading from Oracle.



I have the basic examples all set up and can issue basic queries, and process the results etc..



The problem I'm having is that I need to;




  1. Execute one query (Q1)

  2. For each item in the results of Q1 I need to execute a second query (Q2)

  3. I need to combine the results of Q1 and Q2s into an array to return as a promise


I am struggling to find an example where I can perform #2 - call the same query multiple times for each item returned from Q1, using the same connection which was used for Q1.



My code is below - I first perform a read, then iterate through the results storing connection.execute objects which I then run via the Promise.all line - the result of which I just output as I want to get this working before I code the logic to combine the results of Q1 and Q2.



When I run this via mocha, the results of don't contain any data - I see the column headings but no data.



So what am I missing here?



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

});









share|improve this question
























  • If you're new to Node, try the async/await style of programming available from Node 7.6 onwards instead of promises (or callbacks). There is a node-oracledb sample in example.js
    – Christopher Jones
    Nov 21 at 3:25
















0














I'm new to Node and am having problems reading from Oracle.



I have the basic examples all set up and can issue basic queries, and process the results etc..



The problem I'm having is that I need to;




  1. Execute one query (Q1)

  2. For each item in the results of Q1 I need to execute a second query (Q2)

  3. I need to combine the results of Q1 and Q2s into an array to return as a promise


I am struggling to find an example where I can perform #2 - call the same query multiple times for each item returned from Q1, using the same connection which was used for Q1.



My code is below - I first perform a read, then iterate through the results storing connection.execute objects which I then run via the Promise.all line - the result of which I just output as I want to get this working before I code the logic to combine the results of Q1 and Q2.



When I run this via mocha, the results of don't contain any data - I see the column headings but no data.



So what am I missing here?



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

});









share|improve this question
























  • If you're new to Node, try the async/await style of programming available from Node 7.6 onwards instead of promises (or callbacks). There is a node-oracledb sample in example.js
    – Christopher Jones
    Nov 21 at 3:25














0












0








0







I'm new to Node and am having problems reading from Oracle.



I have the basic examples all set up and can issue basic queries, and process the results etc..



The problem I'm having is that I need to;




  1. Execute one query (Q1)

  2. For each item in the results of Q1 I need to execute a second query (Q2)

  3. I need to combine the results of Q1 and Q2s into an array to return as a promise


I am struggling to find an example where I can perform #2 - call the same query multiple times for each item returned from Q1, using the same connection which was used for Q1.



My code is below - I first perform a read, then iterate through the results storing connection.execute objects which I then run via the Promise.all line - the result of which I just output as I want to get this working before I code the logic to combine the results of Q1 and Q2.



When I run this via mocha, the results of don't contain any data - I see the column headings but no data.



So what am I missing here?



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

});









share|improve this question















I'm new to Node and am having problems reading from Oracle.



I have the basic examples all set up and can issue basic queries, and process the results etc..



The problem I'm having is that I need to;




  1. Execute one query (Q1)

  2. For each item in the results of Q1 I need to execute a second query (Q2)

  3. I need to combine the results of Q1 and Q2s into an array to return as a promise


I am struggling to find an example where I can perform #2 - call the same query multiple times for each item returned from Q1, using the same connection which was used for Q1.



My code is below - I first perform a read, then iterate through the results storing connection.execute objects which I then run via the Promise.all line - the result of which I just output as I want to get this working before I code the logic to combine the results of Q1 and Q2.



When I run this via mocha, the results of don't contain any data - I see the column headings but no data.



So what am I missing here?



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

});






node.js promise es6-promise oracledb oracledb-npm






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 20 at 21:12

























asked Nov 20 at 19:52









bicster

56129




56129












  • If you're new to Node, try the async/await style of programming available from Node 7.6 onwards instead of promises (or callbacks). There is a node-oracledb sample in example.js
    – Christopher Jones
    Nov 21 at 3:25


















  • If you're new to Node, try the async/await style of programming available from Node 7.6 onwards instead of promises (or callbacks). There is a node-oracledb sample in example.js
    – Christopher Jones
    Nov 21 at 3:25
















If you're new to Node, try the async/await style of programming available from Node 7.6 onwards instead of promises (or callbacks). There is a node-oracledb sample in example.js
– Christopher Jones
Nov 21 at 3:25




If you're new to Node, try the async/await style of programming available from Node 7.6 onwards instead of promises (or callbacks). There is a node-oracledb sample in example.js
– Christopher Jones
Nov 21 at 3:25












2 Answers
2






active

oldest

votes


















0














One problem is the Promise.all().then... function doesn't return anything (and doesn't need the additional resolve()). The way to get this sorted is build small, testable, promise returning functions, and test them individually.



Starting simply, write a mocha test to connect to the database...



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


Here's one that can run a command on the db. Test this with a simple query that you know will return some results.



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


With just these two (and one more) we can outline a simple function that does the job: connect to the database, run a select, process each result asynchronously, then disconnect.



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


The last thing to build and test is a promise-returning function which processes a row from the main function above.



I had to take some liberty with this, but I think the objective is -- given a row representing a "case" -- build a case object, including a collection of "concernedRoles" that can be queried with the caseID. (that last bit was my idea, but you can build a separate collection if you like)



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





share|improve this answer























  • This is awesome - thank you!
    – bicster
    Nov 21 at 2:43










  • Note that Oracle connections can process only one statement at a time, so a promise.all() that only uses the same connection for all statements will not actually execute in parallel. This is sometimes good, since it stops the DB being thrashed.
    – Christopher Jones
    Nov 21 at 3:27










  • So I got this working with in my own application - and danh you were right to assume what you did about the relationship of concernroles to cases. Before I go any further I want to make sure I understand the secret sauce here, which is the Promise.all() line. My understanding of this is; for each row in the results of the first SQL query (i.e. for each case) - return a promise containing the definition of the processCaseRow query (with appropriate parameters) - these promises are all stored in a promise array called 'promises'. The promises array is passed to Promise.all() which...
    – bicster
    Nov 21 at 18:10












  • ...invokes those functions in parallel and resolves when all the promises are resolved (i.e. all the processCaseRow calls have been called and successfully returned ) and then passes an array of those results to the next then() which closes the connection and results the final result to the caller of connectAndQuery.....is that right?
    – bicster
    Nov 21 at 18:14












  • @bicster - exactly right, though please note the ChristopherJones comment that the "parallel" promises will end up getting single-threaded through the db connection.
    – danh
    Nov 21 at 18:22



















0














Promise.all will not work for you as you want to use a single connection and as mentioned previously a connection will only do one thing at a time anyway. To solve this problem using promises, you'd have to build up and unwind a promise chain. I can show you an example, but it's nasty - probably better to just forget I mentioned it.



A better option would be to go into a simple for loop using async/await. I can show you can example of that too but again, I think this is the wrong move. We call this row by row fetching (a.k.a slow by slow).



It's likely the best solution for you will be to take the results from the first query and build up an array. Then execute the second query using one of these options to process the array. https://oracle.github.io/node-oracledb/doc/api.html#sqlwherein



You'll need to include the caseid column in the select clause and perhaps even order by that column so that post-processing of the result set is simplified in Node.js.



This solution has the potential to greatly improve performance and resource utilization, but that has to be balanced against the amount of data you have, the resources, etc. I could probably show you an example of this too, but it will take a bit longer and I'd want to get some more info from you to ensure we're on the right path.






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53400570%2fmultple-sql-queries-in-node-with-oracledb%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    One problem is the Promise.all().then... function doesn't return anything (and doesn't need the additional resolve()). The way to get this sorted is build small, testable, promise returning functions, and test them individually.



    Starting simply, write a mocha test to connect to the database...



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


    Here's one that can run a command on the db. Test this with a simple query that you know will return some results.



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


    With just these two (and one more) we can outline a simple function that does the job: connect to the database, run a select, process each result asynchronously, then disconnect.



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


    The last thing to build and test is a promise-returning function which processes a row from the main function above.



    I had to take some liberty with this, but I think the objective is -- given a row representing a "case" -- build a case object, including a collection of "concernedRoles" that can be queried with the caseID. (that last bit was my idea, but you can build a separate collection if you like)



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





    share|improve this answer























    • This is awesome - thank you!
      – bicster
      Nov 21 at 2:43










    • Note that Oracle connections can process only one statement at a time, so a promise.all() that only uses the same connection for all statements will not actually execute in parallel. This is sometimes good, since it stops the DB being thrashed.
      – Christopher Jones
      Nov 21 at 3:27










    • So I got this working with in my own application - and danh you were right to assume what you did about the relationship of concernroles to cases. Before I go any further I want to make sure I understand the secret sauce here, which is the Promise.all() line. My understanding of this is; for each row in the results of the first SQL query (i.e. for each case) - return a promise containing the definition of the processCaseRow query (with appropriate parameters) - these promises are all stored in a promise array called 'promises'. The promises array is passed to Promise.all() which...
      – bicster
      Nov 21 at 18:10












    • ...invokes those functions in parallel and resolves when all the promises are resolved (i.e. all the processCaseRow calls have been called and successfully returned ) and then passes an array of those results to the next then() which closes the connection and results the final result to the caller of connectAndQuery.....is that right?
      – bicster
      Nov 21 at 18:14












    • @bicster - exactly right, though please note the ChristopherJones comment that the "parallel" promises will end up getting single-threaded through the db connection.
      – danh
      Nov 21 at 18:22
















    0














    One problem is the Promise.all().then... function doesn't return anything (and doesn't need the additional resolve()). The way to get this sorted is build small, testable, promise returning functions, and test them individually.



    Starting simply, write a mocha test to connect to the database...



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


    Here's one that can run a command on the db. Test this with a simple query that you know will return some results.



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


    With just these two (and one more) we can outline a simple function that does the job: connect to the database, run a select, process each result asynchronously, then disconnect.



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


    The last thing to build and test is a promise-returning function which processes a row from the main function above.



    I had to take some liberty with this, but I think the objective is -- given a row representing a "case" -- build a case object, including a collection of "concernedRoles" that can be queried with the caseID. (that last bit was my idea, but you can build a separate collection if you like)



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





    share|improve this answer























    • This is awesome - thank you!
      – bicster
      Nov 21 at 2:43










    • Note that Oracle connections can process only one statement at a time, so a promise.all() that only uses the same connection for all statements will not actually execute in parallel. This is sometimes good, since it stops the DB being thrashed.
      – Christopher Jones
      Nov 21 at 3:27










    • So I got this working with in my own application - and danh you were right to assume what you did about the relationship of concernroles to cases. Before I go any further I want to make sure I understand the secret sauce here, which is the Promise.all() line. My understanding of this is; for each row in the results of the first SQL query (i.e. for each case) - return a promise containing the definition of the processCaseRow query (with appropriate parameters) - these promises are all stored in a promise array called 'promises'. The promises array is passed to Promise.all() which...
      – bicster
      Nov 21 at 18:10












    • ...invokes those functions in parallel and resolves when all the promises are resolved (i.e. all the processCaseRow calls have been called and successfully returned ) and then passes an array of those results to the next then() which closes the connection and results the final result to the caller of connectAndQuery.....is that right?
      – bicster
      Nov 21 at 18:14












    • @bicster - exactly right, though please note the ChristopherJones comment that the "parallel" promises will end up getting single-threaded through the db connection.
      – danh
      Nov 21 at 18:22














    0












    0








    0






    One problem is the Promise.all().then... function doesn't return anything (and doesn't need the additional resolve()). The way to get this sorted is build small, testable, promise returning functions, and test them individually.



    Starting simply, write a mocha test to connect to the database...



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


    Here's one that can run a command on the db. Test this with a simple query that you know will return some results.



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


    With just these two (and one more) we can outline a simple function that does the job: connect to the database, run a select, process each result asynchronously, then disconnect.



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


    The last thing to build and test is a promise-returning function which processes a row from the main function above.



    I had to take some liberty with this, but I think the objective is -- given a row representing a "case" -- build a case object, including a collection of "concernedRoles" that can be queried with the caseID. (that last bit was my idea, but you can build a separate collection if you like)



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





    share|improve this answer














    One problem is the Promise.all().then... function doesn't return anything (and doesn't need the additional resolve()). The way to get this sorted is build small, testable, promise returning functions, and test them individually.



    Starting simply, write a mocha test to connect to the database...



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


    Here's one that can run a command on the db. Test this with a simple query that you know will return some results.



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


    With just these two (and one more) we can outline a simple function that does the job: connect to the database, run a select, process each result asynchronously, then disconnect.



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


    The last thing to build and test is a promise-returning function which processes a row from the main function above.



    I had to take some liberty with this, but I think the objective is -- given a row representing a "case" -- build a case object, including a collection of "concernedRoles" that can be queried with the caseID. (that last bit was my idea, but you can build a separate collection if you like)



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






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 21 at 15:20

























    answered Nov 20 at 22:18









    danh

    48.2k874113




    48.2k874113












    • This is awesome - thank you!
      – bicster
      Nov 21 at 2:43










    • Note that Oracle connections can process only one statement at a time, so a promise.all() that only uses the same connection for all statements will not actually execute in parallel. This is sometimes good, since it stops the DB being thrashed.
      – Christopher Jones
      Nov 21 at 3:27










    • So I got this working with in my own application - and danh you were right to assume what you did about the relationship of concernroles to cases. Before I go any further I want to make sure I understand the secret sauce here, which is the Promise.all() line. My understanding of this is; for each row in the results of the first SQL query (i.e. for each case) - return a promise containing the definition of the processCaseRow query (with appropriate parameters) - these promises are all stored in a promise array called 'promises'. The promises array is passed to Promise.all() which...
      – bicster
      Nov 21 at 18:10












    • ...invokes those functions in parallel and resolves when all the promises are resolved (i.e. all the processCaseRow calls have been called and successfully returned ) and then passes an array of those results to the next then() which closes the connection and results the final result to the caller of connectAndQuery.....is that right?
      – bicster
      Nov 21 at 18:14












    • @bicster - exactly right, though please note the ChristopherJones comment that the "parallel" promises will end up getting single-threaded through the db connection.
      – danh
      Nov 21 at 18:22


















    • This is awesome - thank you!
      – bicster
      Nov 21 at 2:43










    • Note that Oracle connections can process only one statement at a time, so a promise.all() that only uses the same connection for all statements will not actually execute in parallel. This is sometimes good, since it stops the DB being thrashed.
      – Christopher Jones
      Nov 21 at 3:27










    • So I got this working with in my own application - and danh you were right to assume what you did about the relationship of concernroles to cases. Before I go any further I want to make sure I understand the secret sauce here, which is the Promise.all() line. My understanding of this is; for each row in the results of the first SQL query (i.e. for each case) - return a promise containing the definition of the processCaseRow query (with appropriate parameters) - these promises are all stored in a promise array called 'promises'. The promises array is passed to Promise.all() which...
      – bicster
      Nov 21 at 18:10












    • ...invokes those functions in parallel and resolves when all the promises are resolved (i.e. all the processCaseRow calls have been called and successfully returned ) and then passes an array of those results to the next then() which closes the connection and results the final result to the caller of connectAndQuery.....is that right?
      – bicster
      Nov 21 at 18:14












    • @bicster - exactly right, though please note the ChristopherJones comment that the "parallel" promises will end up getting single-threaded through the db connection.
      – danh
      Nov 21 at 18:22
















    This is awesome - thank you!
    – bicster
    Nov 21 at 2:43




    This is awesome - thank you!
    – bicster
    Nov 21 at 2:43












    Note that Oracle connections can process only one statement at a time, so a promise.all() that only uses the same connection for all statements will not actually execute in parallel. This is sometimes good, since it stops the DB being thrashed.
    – Christopher Jones
    Nov 21 at 3:27




    Note that Oracle connections can process only one statement at a time, so a promise.all() that only uses the same connection for all statements will not actually execute in parallel. This is sometimes good, since it stops the DB being thrashed.
    – Christopher Jones
    Nov 21 at 3:27












    So I got this working with in my own application - and danh you were right to assume what you did about the relationship of concernroles to cases. Before I go any further I want to make sure I understand the secret sauce here, which is the Promise.all() line. My understanding of this is; for each row in the results of the first SQL query (i.e. for each case) - return a promise containing the definition of the processCaseRow query (with appropriate parameters) - these promises are all stored in a promise array called 'promises'. The promises array is passed to Promise.all() which...
    – bicster
    Nov 21 at 18:10






    So I got this working with in my own application - and danh you were right to assume what you did about the relationship of concernroles to cases. Before I go any further I want to make sure I understand the secret sauce here, which is the Promise.all() line. My understanding of this is; for each row in the results of the first SQL query (i.e. for each case) - return a promise containing the definition of the processCaseRow query (with appropriate parameters) - these promises are all stored in a promise array called 'promises'. The promises array is passed to Promise.all() which...
    – bicster
    Nov 21 at 18:10














    ...invokes those functions in parallel and resolves when all the promises are resolved (i.e. all the processCaseRow calls have been called and successfully returned ) and then passes an array of those results to the next then() which closes the connection and results the final result to the caller of connectAndQuery.....is that right?
    – bicster
    Nov 21 at 18:14






    ...invokes those functions in parallel and resolves when all the promises are resolved (i.e. all the processCaseRow calls have been called and successfully returned ) and then passes an array of those results to the next then() which closes the connection and results the final result to the caller of connectAndQuery.....is that right?
    – bicster
    Nov 21 at 18:14














    @bicster - exactly right, though please note the ChristopherJones comment that the "parallel" promises will end up getting single-threaded through the db connection.
    – danh
    Nov 21 at 18:22




    @bicster - exactly right, though please note the ChristopherJones comment that the "parallel" promises will end up getting single-threaded through the db connection.
    – danh
    Nov 21 at 18:22













    0














    Promise.all will not work for you as you want to use a single connection and as mentioned previously a connection will only do one thing at a time anyway. To solve this problem using promises, you'd have to build up and unwind a promise chain. I can show you an example, but it's nasty - probably better to just forget I mentioned it.



    A better option would be to go into a simple for loop using async/await. I can show you can example of that too but again, I think this is the wrong move. We call this row by row fetching (a.k.a slow by slow).



    It's likely the best solution for you will be to take the results from the first query and build up an array. Then execute the second query using one of these options to process the array. https://oracle.github.io/node-oracledb/doc/api.html#sqlwherein



    You'll need to include the caseid column in the select clause and perhaps even order by that column so that post-processing of the result set is simplified in Node.js.



    This solution has the potential to greatly improve performance and resource utilization, but that has to be balanced against the amount of data you have, the resources, etc. I could probably show you an example of this too, but it will take a bit longer and I'd want to get some more info from you to ensure we're on the right path.






    share|improve this answer


























      0














      Promise.all will not work for you as you want to use a single connection and as mentioned previously a connection will only do one thing at a time anyway. To solve this problem using promises, you'd have to build up and unwind a promise chain. I can show you an example, but it's nasty - probably better to just forget I mentioned it.



      A better option would be to go into a simple for loop using async/await. I can show you can example of that too but again, I think this is the wrong move. We call this row by row fetching (a.k.a slow by slow).



      It's likely the best solution for you will be to take the results from the first query and build up an array. Then execute the second query using one of these options to process the array. https://oracle.github.io/node-oracledb/doc/api.html#sqlwherein



      You'll need to include the caseid column in the select clause and perhaps even order by that column so that post-processing of the result set is simplified in Node.js.



      This solution has the potential to greatly improve performance and resource utilization, but that has to be balanced against the amount of data you have, the resources, etc. I could probably show you an example of this too, but it will take a bit longer and I'd want to get some more info from you to ensure we're on the right path.






      share|improve this answer
























        0












        0








        0






        Promise.all will not work for you as you want to use a single connection and as mentioned previously a connection will only do one thing at a time anyway. To solve this problem using promises, you'd have to build up and unwind a promise chain. I can show you an example, but it's nasty - probably better to just forget I mentioned it.



        A better option would be to go into a simple for loop using async/await. I can show you can example of that too but again, I think this is the wrong move. We call this row by row fetching (a.k.a slow by slow).



        It's likely the best solution for you will be to take the results from the first query and build up an array. Then execute the second query using one of these options to process the array. https://oracle.github.io/node-oracledb/doc/api.html#sqlwherein



        You'll need to include the caseid column in the select clause and perhaps even order by that column so that post-processing of the result set is simplified in Node.js.



        This solution has the potential to greatly improve performance and resource utilization, but that has to be balanced against the amount of data you have, the resources, etc. I could probably show you an example of this too, but it will take a bit longer and I'd want to get some more info from you to ensure we're on the right path.






        share|improve this answer












        Promise.all will not work for you as you want to use a single connection and as mentioned previously a connection will only do one thing at a time anyway. To solve this problem using promises, you'd have to build up and unwind a promise chain. I can show you an example, but it's nasty - probably better to just forget I mentioned it.



        A better option would be to go into a simple for loop using async/await. I can show you can example of that too but again, I think this is the wrong move. We call this row by row fetching (a.k.a slow by slow).



        It's likely the best solution for you will be to take the results from the first query and build up an array. Then execute the second query using one of these options to process the array. https://oracle.github.io/node-oracledb/doc/api.html#sqlwherein



        You'll need to include the caseid column in the select clause and perhaps even order by that column so that post-processing of the result set is simplified in Node.js.



        This solution has the potential to greatly improve performance and resource utilization, but that has to be balanced against the amount of data you have, the resources, etc. I could probably show you an example of this too, but it will take a bit longer and I'd want to get some more info from you to ensure we're on the right path.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 23 at 5:09









        Dan McGhan

        1,08376




        1,08376






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53400570%2fmultple-sql-queries-in-node-with-oracledb%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Wiesbaden

            Marschland

            Dieringhausen