Asynchrony in a database query - javascript

I have a problem when working with node.js. All have tried to describe in comments to the code.
The first thing I need to build an array of dialogs with some information about the interlocutors and the last meggase.
IM = {
iUserId: false,
socket: false,
checkDialog: function(socket) {
this.socket = socket;
// Returned [{owner: 123, viewer: 432}]
var sql = 'SELECT DISTINCT(`owner_user_id`), `viewer_user_id` FROM `phpfox_mail` WHERE `owner_user_id` = ' + this.iUserId + ' GROUP BY 1,2 UNION SELECT DISTINCT (`viewer_user_id`), `owner_user_id` FROM `phpfox_mail` WHERE `viewer_user_id` = ' + this.iUserId + ' GROUP BY 1,2 ORDER BY 1 ';
connection.query(sql, function(err, rows) {
if (err) throw err;
async.map(rows, function(item, nextParent) {
var sql = 'SELECT `mail_id`, `subject`, `preview`, `owner_user_id`, `viewer_user_id`, `viewer_is_new`, `time_stamp` FROM `phpfox_mail` WHERE (`viewer_user_id` = ' + item.viewer_user_id + ' OR `owner_user_id` = ' + item.viewer_user_id + ') AND (`viewer_user_id` = ' + item.owner_user_id + ' OR `owner_user_id` = ' + item.owner_user_id + ') ORDER BY `mail_id` DESC LIMIT 1';
var dialogs = [];
connection.query(sql, function(err, rows) {
// ???
});
}, function(err, item) {
// Here I have to get the generated array with all the necessary dialogue.
console.log(item);
IM.socket.emit('logger', {text: 'dataIsABuilding', key: 'success'});
IM.socket.emit('dialogsBuilding', item);
});
});
}
};
Objective: To create an array of information about the message and interlocutors.
Scheme:
Get an array with all interlocutors. [{owner_user_id: 5757, viewer_user_id: 5866}, {etc...}]
Using the result of paragraph number 1, to get an array of information on the latest report from the dialogue. [{mail_id: 98, subject: test, owner: 5757, viewer: 5866, timestamp: 123566544}, {etc...}]
Get information about users for the specified identifier (owner_user_id/viewer_user_id).
Collect all the data on the dialogues in the same array.
I stopped at the third paragraph. Namely, I do not know how to consistently obtain information about users who are in the first two arrays.
Please, help my!

I don't believe you are using the async.map function correctly. Unfortunately you are using it so incorrectly that I cannot determine what it is you are actually trying to do. But here is an explanation of how you are misusing, vs the proper use of the async.map function.
Example from the async documentation:
async.map(['file1','file2','file3'], fs.stat, function(err, results){
// results is now an array of stats for each file
});
Let's Simplify this a bit.
async.map(someArray, someFunction, someCallBack);
I believe your problem lies in the someFunction argument. Here is your version of this:
function(item, nextParent) {
var sql = 'SELECT `mail_id`, `subject`, `preview`, `owner_user_id`, `viewer_user_id`, `viewer_is_new`, `time_stamp` FROM `phpfox_mail` WHERE (`viewer_user_id` = ' + item.viewer_user_id + ' OR `owner_user_id` = ' + item.viewer_user_id + ') AND (`viewer_user_id` = ' + item.owner_user_id + ' OR `owner_user_id` = ' + item.owner_user_id + ') ORDER BY `mail_id` DESC LIMIT 1';
var dialogs = [];
connection.query(sql, function(err, rows) {
// ???
});
}
The function for this argument, if we consult the fs.Stat example, should take two arguments, this first is an item from the array we sent into async.map. This part I believe you have right. HOwever, the second argument is a callback, with two arguments. An error, and a set of results. This is the part I think you are messing up. You should call this callback. Internally async.map provides the callback argument, this callback argument is how async.map collects results into the array. Without the call to this, async.map cannot collect the results.
I believe what you want is this:
function(item, someCallBackArgument) {
var sql = 'SELECT `mail_id`, `subject`, `preview`, `owner_user_id`, `viewer_user_id`, `viewer_is_new`, `time_stamp` FROM `phpfox_mail` WHERE (`viewer_user_id` = ' + item.viewer_user_id + ' OR `owner_user_id` = ' + item.viewer_user_id + ') AND (`viewer_user_id` = ' + item.owner_user_id + ' OR `owner_user_id` = ' + item.owner_user_id + ') ORDER BY `mail_id` DESC LIMIT 1';
var dialogs = [];
connection.query(sql, function(err, rows) {
someCallBackArgument(err, rows);
});
}

I'm assuming this is a question about how to use async.map:
I've rewritten your code so it uses callbacks properly:
You will need to adjust the output but this should return you an array with all the data you require.
connection.query(sql, function(err, rows) {
if (err) throw err;
async.map(rows, function(item, callback) {
var sql = 'SELECT `mail_id`, `subject`, `preview`, `owner_user_id`, `viewer_user_id`, `viewer_is_new`, `time_stamp` FROM `phpfox_mail` WHERE (`viewer_user_id` = ' + item.viewer_user_id + ' OR `owner_user_id` = ' + item.viewer_user_id + ') AND (`viewer_user_id` = ' + item.owner_user_id + ' OR `owner_user_id` = ' + item.owner_user_id + ') ORDER BY `mail_id` DESC LIMIT 1';
var dialogs = [];
connection.query(sql, function(err, rows) {
if(err) return callback(err);
callback(null, { item: item, rows: rows} );
});
}, function(err, item) {
// Here I have to get the generated array with all the necessary dialogue.
console.log(JSON.stringify(item));
IM.socket.emit('logger', {text: 'dataIsABuilding', key: 'success'});
IM.socket.emit('dialogsBuilding', item);
});
});

Yes! :)
IM = {
iUserId: false,
socket: false,
checkDialog: function(socket) {
this.socket = socket;
var sql = 'SELECT DISTINCT(`owner_user_id`), `viewer_user_id` FROM `phpfox_mail` WHERE `owner_user_id` = ' + this.iUserId + ' GROUP BY 1,2 UNION SELECT DISTINCT (`viewer_user_id`), `owner_user_id` FROM `phpfox_mail` WHERE `viewer_user_id` = ' + this.iUserId + ' GROUP BY 1,2 ORDER BY 1 ';
connection.query(sql, function(err, rows) {
if (err) throw err;
async.map(rows, function(item, nextParent) {
var sql = 'SELECT `mail_id`, `subject`, `preview`, `owner_user_id`, `viewer_user_id`, `viewer_is_new`, `time_stamp` FROM `phpfox_mail` WHERE (`viewer_user_id` = ' + item.viewer_user_id + ' OR `owner_user_id` = ' + item.viewer_user_id + ') AND (`viewer_user_id` = ' + item.owner_user_id + ' OR `owner_user_id` = ' + item.owner_user_id + ') ORDER BY `mail_id` DESC LIMIT 1;';
var dialogs = [];
connection.query(sql, function(err, rows) {
if(err) return nextParent(err);
nextParent(null, rows[0]);
});
}, function(err, item) {
async.map(item, function(dialog, next) {
connection.query('SELECT `user_name`, `full_name`, `user_profile_image` FROM `phpfox_user` WHERE `user_id` = ' + dialog.owner_user_id, function(err, user) {
next(err, {owner: user[0], dialog: dialog});
});
}, function(err, rows) {
async.map(rows, function(dialog, next) {
connection.query('SELECT `user_name`, `full_name`, `user_profile_image` FROM `phpfox_user` WHERE `user_id` = ' + dialog['dialog']['viewer_user_id'], function(err, user) {
next(err, {viewer: user[0], dialog: dialog['dialog'], owner: dialog['owner']});
});
}, function(err, dialogs) {
console.log(dialogs);
IM.socket.emit('logger', {text: 'dataIsABuilding', key: 'success'});
IM.socket.emit('dialogsBuilding', dialogs);
});
});
});
});
}
And it worked! :)
Screen http://screencloud.net//img/screenshots/411f98a583916a41142c40294fd2ee00.png
But it seems to me, this code - it sucks!

Related

TypeError: req.next is not a function node.js

I cannot seem to figure out this issue, it literally just started happening, no code changed!
TypeError: req.next is not a function
The code is failing on line 120. Here is the corresponding sql query, as well as line 120
// Setup form response endpoint
router.get('/form_submit', function (req, res, next) {
var parentFirstName = req.query.employee_First_name
var parentLastName = req.query.employee_last_name
var parentEmail = req.query.employee_email_address
childFirstName = req.query.Child_name
childLastName = req.query.Child_last_name
var relations = req.query.relations
var number = req.query.phone_number
var allergies = req.query.Allergies
var restrictions = req.query.Dietary_Restrictions
const user = JSON.parse(req.session.passport.user)
var queryw = "SELECT * from table"
var numrows = 0
ibmdb.open(DBCredentials.getDBCredentials(), function (err, conn) {
if (err) return console.log(err);
conn.query(queryw, function (err, data) {
if (err) console.log(err);
else console.log(data);
numrows = data.length
conn.close(function () {
console.log("DOING COUNT:");
var crypto = require("crypto");
var id = crypto.randomBytes(3).toString('hex');
console.log(id)
var realIndex = id
var permission = req.query.permission;
console.log(permission)
if (permission == null || permission == " " + undefined || permission == " undefined" || permission == undefined) {
permission = "No"
console.log("inside permission")
}
if (numrows <= 5) {
var query2="insert into table (FIRST_NAME, LAST_NAME, CHILD_FIRST_NAME, CHILD_LAST_NAME, RELATIONSHIP_CHILD, CONTACT_CELLNUMBER, ALLERGIES, DIETARY_RESTRICTIONS, STATUS, EMAIL, PERMISSION, REALINDEX) Values ('" + parentFirstName + "', '" + parentLastName + "', '" + childFirstName + "', '" + childLastName + "', '" + relations +"', '" + number + "', '" + allergies + "', '" + restrictions + "', 'ACTIVE', '" + parentEmail + "', '" + permission + "', '" + realIndex + "')"
console.log(req.body.permission)
ibmdb.open(DBCredentials.getDBCredentials(), function (err, conn) {
if (err) return console.log(err);
conn.query(query2, function (err, data) {
if (err) console.log(err);
else console.log(data);
conn.close(function () {
console.log(numrows);
const user = JSON.parse(req.session.passport.user)
res.render('done', { title: 'Express', user });
console.log(query2);
res.render('done');
});
});
});
}
else if (numrows > 5) {
console.log('CALLNG WAITLIST')
var query3="insert into table (FIRST_NAME, LAST_NAME, CHILD_FIRST_NAME, CHILD_LAST_NAME, RELATIONSHIP_CHILD, CONTACT_CELLNUMBER, ALLERGIES, DIETARY_RESTRICTIONS, STATUS, EMAIL, PERMISSION, REALINDEX) Values ('" + parentFirstName + "', '" + parentLastName + "', '" + childFirstName + "', '" + childLastName + "', '" + relations +"', '" + number + "', '" + allergies + "', '" + restrictions + "', 'WAITLIST', '" + parentEmail + "', '" + permission + "', '" + realIndex + "')"
ibmdb.open(DBCredentials.getDBCredentials(), function (err, conn) {
if (err) return console.log(err);
conn.query(query3, function (err, data) {
if (err) console.log(err);
else console.log(data);
conn.close(function () {
console.log("GOING INTO ELSE STATEMENT");
console.log("THIS IS THE NUMROW COUNT", numrows)
});
const user = JSON.parse(req.session.passport.user)
console.log(user)
res.render('done', { title: 'done', user: user });
});
});
}
});
});
});
console.log('Attempting to send email')
try {
// Read more here for Message Options https://nodemailer.com/message/
// Please change these to your email
const user = JSON.parse(req.session.passport.user)
const message = {
from: "my email", // <= should be verified and accepted by service provider. ex. 'youremail#'
to: req.query.employee_email_address, //
subject: "Registration for " + user.firstName, // <= email subject ex. 'Test email' var parentFirstName = req.query.employee_First_name
text: "Thank you " + user.firstName + " " + user.lastName + " for registering for ",
};
// send mail with defined transport object
transporter.sendMail(message, (error, info) => {
if (error) {
res.status(500).send(`Failed to Send Email: ${error}`)
}
console.log(`Successfully Sent Email ${info.messageId}`)
res.status(200).send(`Successfully Sent Email ${info.messageId}`)
});
} catch (error) {
console.log(`We failed to send Email: ${error}`)
res.status(500).send(error)
}
JSON.parse(req.session.passport.user)
res.render('done', { title: 'Express', user });
})
Line 120: res.render('done', { title: 'done', user: user });
Why is this happening?
I am not sure what is going wrong. It literally just stopped working. No code changes, nothing.
And yes, I know my code is subject to sql injection. It is being fixed
I find multiple errors here.
You can only perform res.send/res.render once in the same request.
If you need to use both, you must clearly differentiate for what type of request you will return JSON, html, etc, (and call send or render only once)
I think you should read about asynchronous programming, since in this case you are invoking functions that will be executed asynchronously and it may be that you execute res.render when the response has already been sent.

NodeJS and Express; callback on connection query completed

I am trying to insert several records in a mysql database and I need to get each record's ID and send it back to the client. The code I'm using:
app.post('/saveLesson',function(req, res){
var idArray = [];
let sections = JSON.parse(req.body.sections);
for (let i = 0; i < sections.length; i++) {
let sql = 'INSERT INTO sections (title, content, duration) VALUES ("' + sections[i].title + '","' + sections[i].content + '","' + sections[i].duration + '");';
connection.query(sql,
function (error, result) {
if (error) throw error;
idArray.push(result.insertId);
console.log('array in the loop: ' + idArray);
}
);
}
console.log('array out of the loop: ' + idArray);
res.send(idArray);
});
The problem is that the .query method seems to be asynchronous and the following code is executed before the idArray is actually populated:
console.log('array out of the loop: ' + idArray);
res.send(idArray);
What would be the appropriate way to deal with this issue?

NJS-024: memory allocation failed in OracleDB - Nodejs

I am trying to run a query using OracleDB with Nodejs to get the view populated in the UI but I get a NJS-024: memory allocation failed error. Can someone help me out? The view contains 120 columns in total and when I query the view in SQL Developer, it works just fine.
ConnectionPool.js:
var path = require('path');
var oracledb = require('oracledb');
var poolMap = {};
var logger = require(path.join(global.root + '/app/util/logger.js'))();
function createPool(poolName, config, callback) {
oracledb.createPool(
config,
function(err, p) {
if (err){
logger.error(err);
return;
}
poolMap[poolName] = p;
callback(poolMap[poolName]);
}
);
}
function getPool(poolName) {
return poolMap[poolName];
}
module.exports = {
createPool: createPool,
getPool: getPool
};
This is my poolAttributes:
var pool;
oracledb.prefetchRows = 10000;
oracledb.maxRows = 400000;
var poolAttrs = {
user: dbcfg.username,
password: dbcfg.password,
connectString: dbcfg.connectionString,
connectionClass : 'Report API',
poolMin : 3,
poolMax : 10,
poolIncrement: 2,
poolTimeout : 600 //seconds
};
connectionPool.createPool("Reports", poolAttrs, function(connPool){
pool = connPool;
logger.info("Pool created by reports.");
});
This is my code:
router.post('/report/', jsonParser, function (req, res) {
var data = req.body,
startRow = data.startRow,
numRows = data.numRows,
sortCol = data.sortCol,
sortDir = data.sortDir;
var countQuery = 'SELECT COUNT(*) ' +
'FROM this_view ' ;
var query = 'SELECT * ' +
'FROM this_view' ;
var seg,
orderBy,
offset;
orderBy = ' ORDER BY UPPER(' + sortCol + ') ' + sortDir;
offset = ' OFFSET ' + startRow + ' ROWS FETCH NEXT ' + numRows + ' ROWS ONLY';
query += orderBy;
query += offset;
logger.info("Begin: " + (new Date().toString()));
async.parallel({
rows: function (callback) {
pool.getConnection(function (err, connection) {
logger.info("Begin Connection: " + (new Date().toString()));
if (err) {
logger.error(err.message);
return;
}
logger.info("Begin execute: " + (new Date().toString()));
connection.execute(
query,
{},
{
resultSet: true,
prefetchRows: 1000
},
function (err, results) {
logger.info("End execute: " + (new Date().toString()));
var rowsProcessed = 0;
var startTime;
if (err) {
logger.error(err.message);
callback("Something broke in the first thing");
doRelease(connection);
return;
}
var procJson = [];
function fetchRowsFromRS(connection, resultSet, numRows) {
resultSet.getRows(
numRows, // get this many rows
function (err, rows) {
if (err) {
console.error(err);
doClose(connection, resultSet); // always close the result set
} else if (rows.length >= 0) {
/**
* For each row in the result, pushes a new object to the rows array
* In each new object, the key is assigned and the result row value set
*/
for (var i = 0; i < rows.length; i++) {
procJson.push({});
console.log(procJson);
for (var j = 0; j < resultSet.metaData.length; j++) {
procJson[i][resultSet.metaData[j].name.toLowerCase()] = rows[i][j];
}
}
//TODO: Add null handling
logger.info("Send JSON: " + (new Date().toString()));
logger.info("JSON Sent: " + (new Date().toString()));
if (rows.length === numRows) // might be more rows
fetchRowsFromRS(connection, resultSet, numRows);
else
doClose(connection, resultSet); // always close the result set
} else { // no rows
doClose(connection, resultSet); // always close the result set
}
});
}
fetchRowsFromRS(connection, result.resultSet, numRows);
callback(null, procJson);
});
});
},
totalRows: function (callback) {
pool.getConnection(function (err, connection) {
logger.info("Begin Connection: " + (new Date().toString()));
if (err) {
logger.error(err.message);
return;
}
logger.info("Begin execute: " + (new Date().toString()));
connection.execute(
countQuery,
function (err, result) {
logger.info("End execute: " + (new Date().toString()));
if (err) {
logger.error(err.message);
callback("Something broke");
doRelease(connection);
return;
}
logger.info("Send JSON: " + (new Date().toString()));
console.log(result.rows);
callback(null, result.rows[0][0]);
logger.info("JSON Sent: " + (new Date().toString()));
doRelease(connection);
});
});
}
}, function(err, result){
if(err){
logger.error(err);
}
res.send(result);
});
});
If rows.length >=0 and if the query returns 0 results, I get this.
How much memory does your Node.js server have? You're setting maxRows very high and grabbing all the data in a single shot. This is likely causing you to run out of memory. Generally, the key is to balance round trips (which you want to reduce) with memory usage (which goes up as round trips are reduced.
You'll want to leverage the ResultSet API, which allows you to stream a read-consistent view of data in smaller chunks. Have a look at this for ideas: https://jsao.io/2015/07/an-overview-of-result-sets-in-the-nodejs-driver/
Rather than buffer the data in the Node.js server (which would lead to the same problem), you'll want to stream it down to the http request.
Finally, but perhaps most importantly, note that your code is currently open to SQL injection. Values that come in from users via req.body cannot be trusted. They must either be bound in using bind variables OR sanitized using something like dbms_assert.
Only values (like numRows) can be bound in. Identifiers (like sortCol) have to be sanitized. You'll likely want to do the sanitization in Node.js, so here's a really basic check that should help.
You could create an "assert" module:
function simpleSqlName(name) {
if (name.length > 30) {
throw new Error('Not simple SQL');
}
// Fairly generic, but effective. Would need to be adjusted to accommodate quoted identifiers,
// schemas, etc.
if (!/^[a-zA-Z0-9#_$]+$/.test(name)) {
throw new Error('Not simple SQL');
}
return name;
}
module.exports.simpleSqlName = simpleSqlName;
function validSortOrder(order) {
if (order !== 'desc' && order !== 'asc') {
throw new Error('Not valid sort order');
}
return order;
}
module.exports.validSortOrder = validSortOrder;
Then your code would look more like this (notice I'm using both the assert module and bind variables):
let assert = require('assert.js');
router.post('/report/', jsonParser, function (req, res) {
var data = req.body,
startRow = data.startRow,
numRows = data.numRows,
sortCol = assert.simpleSqlName(data.sortCol),
sortDir = assert.validSortOrder(data.sortDir);
var countQuery = 'SELECT COUNT(*) ' +
'FROM this_view ' ;
var query = 'SELECT * ' +
'FROM this_view' ;
var seg,
orderBy,
offset;
orderBy = ' ORDER BY UPPER(' + sortCol + ') ' + sortDir;
offset = ' OFFSET :start_row ROWS FETCH NEXT :num_rows ROWS ONLY';
query += orderBy;
query += offset;
logger.info("Begin: " + (new Date().toString()));
async.parallel({
rows: function (callback) {
pool.getConnection(function (err, connection) {
logger.info("Begin Connection: " + (new Date().toString()));
if (err) {
logger.error(err.message);
return;
}
logger.info("Begin execute: " + (new Date().toString()));
connection.execute(
query,
{
start_row: startRow,
num_rows: numRows
},
function (err, result) {
logger.info("End execute: " + (new Date().toString()));
if (err) {
logger.error(err.message);
callback("Something broke in the first thing");
doRelease(connection);
return;
}
console.log(result.rows);
var procJson = [];
/**
* For each row in the result, pushes a new object to the rows array
* In each new object, the key is assigned and the result row value set
*/
for (var i = 0; i < result.rows.length; i++) {
procJson.push({});
for (var j = 0; j < result.metaData.length; j++) {
procJson[i][result.metaData[j].name.toLowerCase()] = result.rows[i][j];
}
}
logger.info("Send JSON: " + (new Date().toString()));
callback(null, procJson);
logger.info("JSON Sent: " + (new Date().toString()));
doRelease(connection);
});
});
},
totalRows: function (callback) {
pool.getConnection(function (err, connection) {
logger.info("Begin Connection: " + (new Date().toString()));
if (err) {
logger.error(err.message);
return;
}
logger.info("Begin execute: " + (new Date().toString()));
connection.execute(
countQuery,
function (err, result) {
logger.info("End execute: " + (new Date().toString()));
if (err) {
logger.error(err.message);
callback("Something broke");
doRelease(connection);
return;
}
logger.info("Send JSON: " + (new Date().toString()));
console.log(result.rows);
callback(null, result.rows[0][0]);
logger.info("JSON Sent: " + (new Date().toString()));
doRelease(connection);
});
});
}
}, function(err, result){
if(err){
logger.error(err);
}
res.send(result);
});
});
Learn more about bind variables here: https://github.com/oracle/node-oracledb/blob/master/doc/api.md#bind
Also, check out the slides from a recent talk I gave. You may get something out of them... https://www.dropbox.com/s/2rhnu74z2y21gsy/Tips%20and%20Tricks%20for%20Getting%20Started%20with%20the%20Oracle%20Database%20Driver%20for%20Node.pdf?dl=0

Loop through Array and perform My SQL query based on result of previous query for each entry in the array

I have an array of items:
var myArr = ['item1', 'item2', 'item3'];
I'm attempting to loop over these items and check if they exist in my database. If the item does not exist, then I add it to the database.
var sql = 'Select * from DB where item="' + myArr[i] + '"';
connection.query(sql, function(e, r, f) {
if(!e && r.length <= 0) {
performInsertOnDB(myArr[i]);
}
});
My trouble is, the reference to variable i will not stay as connnection.query is asynchronous. I need to wait until the first select finishes before I can continue. I'm trying to use the Async library to accomplish this, but I must not be fully grasping how to perform the task.
This is what I have so far:
async.each(lootArray, function(lootItem, addLootItem) {
var sql = "SELECT * FROM loot_history WHERE date = DATE('" + moment(lootItem[1]).format('YYYY-MM-DD') + "') AND time = '" + lootItem[2] + "' AND itemId = " + lootItem[4];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
return false;
} else {
if (results.length > 0) {
//duplicates.push(lootArray[i]);
} else {
addLootItem(lootItem);
}
}
});
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if (err) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
function addLootItem(lootItem) {
var sql = "INSERT INTO loot_history SET player = " + lootItem[0] + ", date = " + moment(lootItem[1]).format('YYYY-MM-DD') + ", time = '" + lootItem[2] + ", item = " + lootItem[3] + ", itemId = " + lootItem[4] + ", itemString=" + lootItem[5] + ", response= " + lootItem[6] + ", votes= " + lootItem[7] + ", class= " + lootItem[8] + ", instance=" + lootItem[9] + ", boss=" + lootItem[10] + ", gear1=" + lootItem[11] + ", gear2=" + lootItem[12] + ", reasponseId=" + lootItem[13] + ", isAwardReason=" + lootItem[14];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
}
});
}
EDIT: Everything works, except the callback AddLootItem is not firing. Why is this callback not getting called? I can set log events in that if statement that execute, but the function itself never fires.
The problem is that the name of async callback is the same as the function you want to be called when the item does not exist. Try to change the name in the function to something else let's say: callback, and call it in your if statement or pass it to addLootItem, and call it there once the item added.
async.each(lootArray, function(lootItem, callback) {
var sql = "SELECT * FROM loot_history WHERE date = DATE('" + moment(lootItem[1]).format('YYYY-MM-DD') + "') AND time = '" + lootItem[2] + "' AND itemId = " + lootItem[4];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
calback(err);
} else {
if (results.length > 0) {
//duplicates.push(lootArray[i]);
callback();
} else {
addLootItem(lootItem, callback);
}
}
});
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if (err) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
function addLootItem(lootItem, done) {
var sql = "INSERT INTO loot_history SET player = " + lootItem[0] + ", date = " + moment(lootItem[1]).format('YYYY-MM-DD') + ", time = '" + lootItem[2] + ", item = " + lootItem[3] + ", itemId = " + lootItem[4] + ", itemString=" + lootItem[5] + ", response= " + lootItem[6] + ", votes= " + lootItem[7] + ", class= " + lootItem[8] + ", instance=" + lootItem[9] + ", boss=" + lootItem[10] + ", gear1=" + lootItem[11] + ", gear2=" + lootItem[12] + ", reasponseId=" + lootItem[13] + ", isAwardReason=" + lootItem[14];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
}
done();
});
}

MySQL, Node.js Sequential actions - How can I do that?

I've the following code:
function query1() {
var defered = Q.defer();
console.log("In query1");
var connection = mysql.createConnection({
host: '........',
user: 'm...c....a.....i',
password: '......Z....9...K',
database: '.....ol'
});
connection.connect(function(err) {
if (!err) {
console.log("Database is connected ...");
} else {
console.log("Error connecting database ...");
}
});
sql = '' +
'select c.ID as CENA_ID, ' +
' c.I_KEY as CENA_NUMERO, ' +
' c.NM_CENA as CENA_NOME, ' +
' b.DS_MAC as MAC_BOX, ' +
' v.DS_CLIENTID as ALEXA_ID, ' +
' v.FK_ID_GRUPO as GRUPO_ID ' +
' from TB_DISPOSITIVOS_VOZ v ' +
' inner join TB_GRUPOS g ' +
' on g.ID = v.FK_ID_GRUPO ' +
' inner join TB_CENAS c ' +
' on g.ID = c.FK_ID_GRUPO ' +
' inner join TB_CENTRAIS b ' +
' on g.ID = b.FK_ID_GRUPO ' +
'where v.DS_CLIENTID = "' + userId + '" ' +
'and lower(c.NM_CENA) like "%' + sceneName.toLowerCase() + '%"';
console.log("Created query");
try{
connection.query(sql, function(erro, rows, fields) {
if (!erro) {
console.log("Executed query verifying the userId");
contador = 0;
if (rows.length > 0) {
cena_id = rows[0].CENA_ID;
cena_numero = rows[0].CENA_NUMERO;
cena_nome = rows[0].CENA_NOME;
alexa_id = rows[0].ALEXA_ID;
grupo_id = rows[0].GRUPO_ID;
mac_box = rows[0].MAC_BOX;
contador = contador + 1;
}
console.log("contador: " + contador);
} else {
console.log("Error - getting the Alexa register in database" + erro);
context.fail("Error - getting the Alexa register in database" + erro);
}
});
}catch (ex){
console.log("exception: " + ex);
}
}
And this code as well:
Q.all([query1()]).then(function(results) {
console.log("Q.all log function");
if (contador > 0) {
console.log("contador > 0");
var client = mqtt.connect('mqtt://.............com');
console.log("connected to MQTT broker");
var buffer = [26,
0,0,0,0,555,645,0,0,0,0,0,
0,5555,2,Math.floor((Math.random() * 200) + 1),
0,0,0,333,13,4,0,1,0,
cena_numero
];
console.log("Created buffer");
client.on('connect', function() {
client.publish('n/c/' + mac_box + '/app', buffer);
console.log("sent MQTT");
});
speechOutput = "Command " + sceneName + " executed successfully";
repromptText = "";
console.log("Process executed successfully")
} else {
console.log("contador <= 0");
speechOutput = "This command was not found!";
repromptText = "";
}
}, function (reason) {
console.log("reason: " + reason);
});
How can I do for the second code execute only if the first query1() executed correctly? Because in the function query1() i've a MySQL Query, and I only can continue with the process after the result of this query.
Anyone can help me?
Thanks a lot!
You're missing some key concepts regarding callbacks and asynchronous behavior in Node.js. You're using the "Q" library (btw I'd recommend trying bluebird instead) to handle promises, but your "query1" function does not return a promise. That's why query1 executes but your "Q.all log function" will execute before query1 is finished.
You can structure your code like this instead (I'll give an example with bluebird since I'm more familiar with it):
var Promise = require('bluebird');
var _connection;
function query1() {
return new Promise(resolve, reject) {
//open your connection
connection.open(function (err, connection) {
if (err) return reject(err);
_connection = connection;
//do your query
_connection.query(sql, [params], function (err, data) {
if (err) return reject(err);
else resolve(data);
});
});
});
}
function query2(data) {
return new Promise(resolve, reject) {
//do your query, using data passed in from query1
_connection.query(sql, [params], function (err, data) {
if (err) return reject(err);
else resolve(data);
});
});
}
query1
.then(function (data) { query2(data); })
.catch(function (err) {
console.log('error:', err);
});
Also, just FYI, concatenating SQL string like this is a no-no that will open you up to a SQL injection attack:
like "%' + sceneName.toLowerCase() + '%"
Instead, use like "%?%" and call your SQL with connection.query(sql, [sceneName], function(err, data) {}). Hope this helps.
I solved my problem with asyncpackage like this:
var async = require('async');
async.series([
function(callback) {
//action 1...
},
function(callback){
//action 2...
}
], function(err) {
if (err) {
speechOutput = "Scene not found!";
repromptText = "Please try again.";
}
console.log("Before speechOutput");
callback(sessionAttributes,
buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
});

Categories

Resources