Here is the code, and when I run it, it only executes once...
export const postStock = (body) => {
for (let val of body.order.values()) {
let sql = ` INSERT INTO stockmaster (stocknum, cat_id, user_id, dyenumber, stockQty) VALUES ('${body.stocknum}', ${JSON.stringify(val.cat_id)}, '${body.user_id}', ${JSON.stringify(val.dyenumber)}, ${JSON.stringify(val.stockQty)})`;
return sql;
};
};
So, how do I run the for loop or prevent it from stopping?
Look at how the function works, and when the loop starts, it sends the response multiple times, so I tried to set it outside of the loop, but if I set it outside of the loop, how can I send an error in response?
So now I'm stuck here...!
static stock = async (req, res) => {
for (let i = 0; i < req.body.order.length; i++) {
const body = req.body;
connection.query(postStock(body, body.order[i]), (err, result) => {
if (err) {
res.status(500).json({
code: 0,
msg: "Fail",
emsg: "Server error: " + err.message
});
} else {
connection.query(updatepStock(body.order[i]), async (err, result) => {
if (err) {
res.status(500).json({
code: 0,
msg: "Fail",
emsg: "Server error: " + err.message
});
}
})
}
})
}
res.status(201).json({code: 1,msg: "success",emsg: "Stock arrived & Product Stock updated successfully"
})
}
return stops execution and exits the function. return always exits its function immediately, with no further execution if it's inside a for loop.
So you should avoid return in case you want the loop to continue. What you can do is store the sql into array or print the data without returning anything
You can use this. return makes the loop function to exit.
export const postStock = (body) => {
let values = body.order.values();
let sql = values.map((val) => `("${body.stocknum}",
"${JSON.stringify(val.cat_id)}", "${body.user_id}",
"${JSON.stringify(val.dyenumber)}", "${JSON.stringify(val.stockQty)}")`)
let query = "INSERT INTO stockmaster (stocknum, cat_id, user_id, dyenumber,
stockQty) VALUES " + sql
}
Related
I am creating a simple web application and am stuck on a simple problem. I want to update the temp variable from the results of my inner query. I know that connection.query might take some time, so the rest of the code is executed first. In the final response, I am not getting the value of temp.user_image and temp.user_name.
router.get("/home/getArticles", (req, res) => {
var select_query = "SELECT * FROM `articles` WHERE 1";
connection.query(select_query, async (err, result) => {
if (err) {
return res.status(500).json({ message: "Error while processing your request" });
}
var final_data = [];
for (var i = 0; i < result.length; i++) {
var temp = {};
let current_user_id = result[i].user_id;
var select_query = "SELECT * FROM `users` WHERE `user_id`=" + mysql.escape(current_user_id) + "";
connection.query(select_query, (err, innerResult) => {
if (err) throw err;
temp.user_name = innerResult[0].user_name;
temp.user_image = innerResult[0].user_profile_image;
});
temp.title = result[i].title;
temp.body = result[i].detail;
final_data.push(temp);
}
return res.status(200).json({ data: final_data });
})
})
There are 2 problems in your code:
The server response before the second query finish - which you've already known.
This way of querying relationship will result in extremely bad performance known as N+1 query problem
For an example, we can use SQL JOIN clause for querying relationship:
router.get("/home/getArticles", (req, res) => {
var select_query = "SELECT articles.*, users.user_name, users.user_profile_image AS user_image FROM `articles` LEFT JOIN `users` ON `articles`.`user_id` = `users`.`id` WHERE 1";
connection.query(select_query, async (err, result) => {
if (err) {
return res.status(500).json({ message: "Error while processing your request" });
}
return res.status(200).json({ data: result });
})
})
In an Express JS connected to a mySQL db, I am trying to get some data of an already defined route/ query:
// customers.model.js
CUSTOMERS.getAll = (result) => {
let query = "SELECT * FROM customers"
sql.query(query, (err, res) => {
if (err) {
console.log("error: ", err)
result(null, err)
return
}
result(null, res)
})
}
// customers.controller.js
// GET customers is a standalone route and should output all the customers when called.
const CUSTOMERS = require("../models/customers.model.js")
exports.findAll = (req, res) => {
return CUSTOMERS.getAll((err, data) => {
if (err)
res.status(500).send({
message: err.message ||
"Some error occurred while retrieving customers...",
})
else res.send(data)
})
}
In payments.controller.js I would firstly like to get all users so I can do something with the data:
// payments.controller.js
// GET payments is also a standalone route and should get the customers,
// do something with the data and output a calculation with the help of this data
const CUSTOMERS = require("../models/customers.model.js")
exports.calculateAll = (req, res) => {
const customers = CUSTOMERS.getAll((err, data) => {
console.log('this always has correct data', data)
if (err) return err
else return data
})
console.log('this is always undefined', customers)
...
res.send(whatEverCalculatedData)...
}
But that data here is always undefined.
What am I doing wrong in the above, and what's the correct way to call this route inside another route?
I know it has similarities with this question but I couldn't sort it out for my particular example.
It's due to your call which is asynchronous.
You must wait your data being ready before rendering the results.
Maybe you could to use Promises or async/await statements.
For example:
CUSTOMERS.getAll = async () => {
const query = "SELECT * FROM customers";
try {
return await sql.query(query);
} catch (e) {
console.log(`An error occurred while fetching customers: ${e.message}.`);
return null;
}
}
exports.calculateAll = async (req, res) => {
try {
const data = await CUSTOMERS.getAll();
res.send(whatEverCalculatedData);
} catch (e) {
res.send(`Something went wront: ${e.message}.`);
}
}
Working in a NodeJS that saves data to a SQL Server Database, it must save data from an array of objects but when I run it I get this error, just looked here and documentation but I don't really understand how to fix it, any help is welcomed. This is the error:
PS D:\Users\****\****\****\****\****> node appb.js
Successful connection
events.js:135
throw new ERR_INVALID_ARG_TYPE('listener', 'Function', listener);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "listener" argument must be of type function. Received type string ('row')
And this is my app.js:
Connection:
var Connection = require("tedious").Connection;
var lstValid = [];
var config = {
server: "SERVER",
authentication: {
type: "default",
options: {
userName: "USERNAME",
password: "PASSWORD",
},
},
options: {
encrypt: true,
database: "DATABASE",
instanceName: 'INSTANCENAME'
},
};
var connection = new Connection(config);
connection.on("connect", function (err) {
console.log("Successful connection");
executeStatement1();
});
connection.connect();
and here's where I insert data:
async function calcWeather() {
const info = await fetch("../json/data.json")
.then(function (response) {
return response.json();
});
for (var i in info) {
const _idOficina = info[i][0].IdOficina;
const lat = info[i][0].latjson;
const long = info[i][0].lonjson;
const base = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${long}&appid=${api_key}&units=metric&lang=sp`;
fetch(base)
.then((responses) => {
return responses.json();
})
.then((data) => {
var myObject = {
Id_Oficina: _idOficina,
// Other thins in myObject
};
// validation and saving data to array
if (myObject.Temperatura < 99) {
lstValid.push(myObject);
}
});
}
}
var Request = require("tedious").Request;
var TYPES = require("tedious").TYPES;
function executeStatement1() {
calcWeather();
for (var m = 0; m <= lstValid.length; m++) {
Request = new Request(
"INSERT INTO TB_BI_CSL_RegistroTemperaturaXidOdicina (IdOficina, Humedad, Nubes, Sensacion, Temperatura, Descripcion) VALUES (#IdOficina, #Humedad, #Nubes, #Sensacion, #Temperatura)",
function (err) {
if (err) {
console.log("Couldn't insert data: " + err);
}
}
);
Request.addParameter("IdOficina", TYPES.SmallInt, lstValid[m]);
// Other things inserted
Request.on('requestCompleted',"row", function (columns) {
columns.forEach(function (column) {
if (column.value === null) {
console.log("NULL");
} else {
console.log("Product id of inserted item is " + column.value);
}
});
});
Request.on("requestCompleted", function (rowCount, more) {
connection.close();
});
connection.execSql(Request);
}
}
Seems that there are too many parameters to the request.on(...) method, i.e.:
Request.on('requestCompleted',"row", function (columns)
Should probably be:
Request.on("row", function (columns)
The error says the JavaScript function received arguments that were different than expected:
...ERR_INVALID_ARG_TYPE('listener', 'Function', listener);
If it has never worked, the function was likely mistyped. (If it has worked, it could be bad data coming in)
The next message gives a further information:
"...The "listener" argument must be of type function. Received type string ('row')"
A JavaScript function to do work was expected, but it received a simple string 'row' instead.
events.js:135
This means the error happened in the file 'events.js' on or before line 135.
The TediusJs API Request Docs, provides a reference example:
request.on('row', function (columns) { /* code to process rows */ });
In your example we find:
Request.on('requestCompleted',"row", function (columns) {
Most likely it should be:
Request.on("row", function (columns) {
Although I am not positive which line in your example is line 135.
I have an array that I am trying to return but only return certain rows within that array if the column Free_Agent is populated (or I could do if Years_Kept is greater than or equal to 2).
Here is my code where I have been able to successfully return the values of the array by a console log. Everything I try when I either try to do a forEach or pull the filtered data via a filter view I have set up (363219995) will not work.
async function gsrun(cl){
const gsapi = google.sheets({version:'v4', auth: cl });
gsapi.spreadsheets.values.get({
spreadsheetId: "11e5nFk50pDztDLngwTSmossJaNXNAGOaLqaGDEwrbQM",
range: 'Keepers!C1:F',
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const rows = res.data.values;
if (rows.length) {
rows.map((row) => {
console.log(`${row[0]}, ${row[1]}, ${row[2]}, ${row[3]}`);
});
} else {
console.log('No data found.');
}
})
};
Terminal Screenshot of mapped Array
Can anybody please help a newbie? I've been teaching myself and watching videos and reading everything I can, I just can't seem to grasp it.
You have to filter the values (rows) arrays to check if there is a value.
async function gsrun(cl){
const gsapi = google.sheets({version:'v4', auth: cl });
gsapi.spreadsheets.values.get({
spreadsheetId: "11e5nFk50pDztDLngwTSmossJaNXNAGOaLqaGDEwrbQM",
range: 'Keepers!C1:F',
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const rows = res.data.values;
if (rows.length) {
const cells = rows.filter(cell => cell[3])
cells.map((cell) => {
console.log(`${cell[0]}, ${cell[1]}, ${cell[2]}, ${cell[3]}`);
});
} else {
console.log('No data found.');
}
})
};
Just adding to #ArthurCosta's answer, based on the second condition you provided.
async function gsrun(cl){
const gsapi = google.sheets({version:'v4', auth: cl });
gsapi.spreadsheets.values.get({
spreadsheetId: "11e5nFk50pDztDLngwTSmossJaNXNAGOaLqaGDEwrbQM",
range: 'Keepers!C1:F',
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const rows = res.data.values;
if (rows.length) {
const cells = rows.filter(cell => cell[3] || (parseInt(cell[2]) >= 2))
cells.map((cell) => {
console.log(`${cell[0]}, ${cell[1]}, ${cell[2]}, ${cell[3]}`);
});
} else {
console.log('No data found.');
}
})
};
I'm having severe doubts that the code I'm writing is an efficient/best way to achieve my goal.
I have a promise which makes an SQL query, after it's completed I loop through an array and it's sub arrays+objects. Even if any of the subloops fail for any specific reason I want the inner loops to continue executing until the entire array has been looped through. Right now I have a "try/catch" hell which I doubt is the correct way to do this. I should however say that it works as expected, but how bad code is it?
new Promise((resolve, reject) => {
sqlConnection.execute(
'INSERT INTO pms (userId, message, conversationId) VALUES (?, ?, ?)',
[userid, receivedMsg, receivedConvId],
function(err, results) {
if (err) throw err;
resolve("DEBUG: PM from "+username+" into conv "+receivedConvId+" was sucessfully inserted to DB");
}
);
}).then(() => {
users.forEach(function(userobj, i, arr) {
try {
if (userobj.memberof.includes(receivedConvId)) {
let rcptUsername = userobj.username;
let rcptUserid = userobj.userid;
debug(rcptUsername+" is member of the group "+receivedConvId);
Object.keys(userobj.sessions).forEach(function(session) {
try {
userobj.sessions[session].forEach(function(wsConn) {
try {
debug("DEBUG: Broadcasting message to "+rcptUsername+" for connections inside session "+session);
wsConn.send(JSON.stringify(msgToSend));
} catch(err) {
errorHandler(err);
}
});
} catch(err) {
errorHandler(err);
}
});
}
} catch(err) {
errorHandler(err);
}
});
}).catch((err) => {
debug(err);
}).then(() => {
debug("INFO: Message broadcast finished");
});
The array I'm looping through could look like this:
[
{ username: 'Root',
userid: '1',
memberof: [ 1, 2, 3 ],
sessions:
{
pvkjhkjhkj21kj1hes5: [Array],
'4duihy21hkk1jhhbbu52': [Array]
}
},
{
username: 'Admin',
userid: '2',
memberof: [ 1, 2, 4 ],
sessions:
{
cg2iouoiuiou111uuok7: [Array],
sl1l3k4ljkjlkmmmmkllkl: [Array]
}
}
]
Grateful for any advice.
Assuming wsConn is a https://github.com/websockets/ws websocket - then the code you are using will only ever "detect" immediate errors anyway - any socket write failures will not be caught
You'll also be outputting "INFO: Message broadcast finished" before any of the wsConn.send have finished - because it's asynchronous
Fortunately .send has a callback, which is called back on errors or success once the send has completed - this solves both issues
Using promises is a good idea, except you haven't used promises for anything but the initial SQL execute, which is why you've ended up in nesting hell
I'm fairly confident (without your full code I can't be sure) that the following code will not only run, it has far less nesting
new Promise((resolve, reject) => {
sqlConnection.execute(
'INSERT INTO pms (userId, message, conversationId) VALUES (?, ?, ?)',
[userid, receivedMsg, receivedConvId],
(err, results) => {
if (err) {
return reject(err);
}
resolve("DEBUG: PM from " + username + " into conv " + receivedConvId + " was sucessfully inserted to DB");
}
);
}).then(() => {
const allConnectionsArray = users
.filter(({memberof}) => memberof.includes(receivedConvId)) // filter out any userobj we aren't going to send to
.map(({rcptUsername, rcptUserid, sessions}) => {
debug(rcptUsername + " is member of the group " + receivedConvId);
const userSessionsArray = Object.entries(sessions).map(([session, value]) => {
return value.map((wsConn, index) => {
return { wsConn, rcptUserid, rcptUsername, session, index };
})
});
return [].concat(...userSessionsArray); // flatten the array
});
const promises = [].concat(...allConnectionsArray) // flatten the array
.map(({ wsConn, rcptUserid, rcptUsername, session, index }) => {
debug("DEBUG: Broadcasting message to " + rcptUsername + " for connections inside session " + session);
return new Promise((resolve) => {
wsConn.send(JSON.stringify(msgToSend), err => {
if (err) {
return resolve({ rcptUserid, rcptUsername, session, index, err });
}
resolve({ rcptUserid, rcptUsername, session, index, err: false });
});
});
});
return Promise.all(promises);
}).then(results => {
/* results is an array of {
rcptUserid
rcptUsername
session
index //(index is the ordinal position in user.sessions array
err //(===false if success)
}
*/
debug("INFO: Message broadcast finished");
}).catch(error => {
// the only error caught here would be in the `return reject(err);` in the sql execute,
// because any failure in wsConn.send is a resolved promise (with an error property)
// unless I'm not seeing something obvious, they are the only possible places an error could be thrown anyway
});