filled array is empty when send back to user - javascript

I try to get data from an azure database with SQL and for this I use tedious. When I execute the code, the array "result" gets filled up with data but when de respond sends the array "result" to the user it is empty. Why and how can I solve it? (I want to send it back in JSON format, the legth is unknown I use 5 to debug).
This is my code
router.get('/', async (req, res) => {
result = []
let rowData = {}
const request = new Request(
`SELECT TOP (5) [LogID]
,[OpdrachtID]
,[ChangeLog]
,[TimeStamp]
,[PersonID]
FROM [log].[LOpdracht]`,
function (err, rowCount, rows) {
if (err) throw err
})
connection.execSql(request)
request.on('row', function(columns){
rowData = {}
columns.forEach(function(column){
rowData[column.metadata.colName] = column.value
})
result.push(rowData)
})
res.send(result)
})

Looks like you are using Tedious. If that is so then you can use the 'done' event to be notified when the request has completed and all rows have been read into result.
request.on('done', () => res.send(result));
Update: As the note in the documentation points out, since you are using execSql you will need to listen to doneProc and doneInProc instead:
request.on('doneProc', () => res.send(result));
request.on('doneInProc', () => res.send(result));

I solved it by adding this:
request.on('requestCompleted', () => {
res.send(result)
})

Related

I'm unable to send a response to my react.js using http.get in node

I'm trying to get the temperature data from my node.js backend sent to react.js but i kept getting res.send is not a funtion
Sample code here
app.get("/gettemperature", (req, res) => {
const email = req.query.email;
let stmt = `SELECT * FROM users WHERE email=?`;
let todo = [email];
db.query(stmt, todo, (err, results, fields) => {
if (err) {
console.error(err.message);
}
if(results.length > 0 ){
let id = results[0].id;
let getID = `SELECT * FROM controlModules WHERE deviceowner=?`;
let getidData = [id];
db.query(getID, getidData, (err, resulta, fields) => {
if (err) {
console.error(err.message);
}
if(resulta.length > 0){
let lanip = resulta[0].ipaddress;
let url = "http://"+lanip+"/data";
http.get(url,(res) => {
let body = "";
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
try {
let json = JSON.parse(body);
const temp_actual = json.temperature.value;
console.log(temp_actual);
res.setHeader('Content-Type', 'application/json');
res.end(
JSON.stringify({
value: temp_actual
})
);
} catch (error) {
console.error(error.message);
};
});
}).on("error", (error) => {
console.error(error.message);
});
}
});
}
});
});
i really need to return/send/respond the temperature data to my front end but i'm getting said error, is there a different way to return data?
It looks like you are mixing up an HTTP server you wrote in Node (although you haven't shown any relevant code) and an HTTP client you also wrote in Node.
res is an argument received by the callback you pass to http.get and contains data about the response received by your HTTP client.
Meanwhile, somewhere else (not shown) you have a different variable also called res which is the object your HTTP server uses to send its response to the browser running your React code.
You are calling res.send and wanting res to be the latter but it is really the former.
Since you haven't shown us the HTTP server code, it is hard to say where that res is, but there is a good chance you have shadowed it and can solve your problem by using different names (e.g. client_res and server_res).
That said. I strongly recommend avoiding using the http module directly as the API follows out of date design patterns and isn't very friendly. Consider using fetch or axios for making HTTP requests and Express.js for writing HTTP servers.

Axios Post is not completing every time

Iam new to React and I got some problems.
This is my current API call.
Axios.post(Addr_currentRound_addOne, { gameId: gameId }).then(history.push("/leiter_tunierplan/"+gameId));
And this is the corresponding API Code snippet.
app.post("/currentRoundAddOne", (req, res) => {
const gameId = req.body.gameId;
db.query(
"UPDATE tunierplan SET currentRound=currentRound+1 WHERE id=?;",
[gameId],
(err, result) => {
if (err) {
console.log(err);
} else {
res.send("Daten Übertragen");
}
}
);
});
The problem here:
currentRound, should allways when the call is executed increased by +1.
And then Redirect to the given "/leiter_tunierplan/"
BUT
From time to time, it does not work. Its not increasing it by any Value (+1)
My first thought is: Because its async it my be canceled from the history.push, befor it got completed. Am i right? And how can i fix it.
Thanks allready.
Is game gameId the already incremented id for the next page? I don't see it being incremented anywhere in your code.
If so, try putting history.push in a callback, like this:
...then(() => history.push("/leiter_tunierplan/"+gameId));
This is because then takes a callback function as a parameter
The Solution to all is to add preventDefault();
My Problem was, that the side got reloaded..
I think you try async-await as the request to the database is promise-based.
My suggestion:
app.post("/currentRoundAddOne", async (req, res) => {
const gameId = req.body.gameId
const data = await db.query("UPDATE tunierplan SET currentRound=currentRound+1 WHERE id=?;", [gameId],
(err, result) => {
if (err) console.log(err);
}
console.log(data) // check updated data, it should return id
})
I hope it works!

Test all functions that have been terminated

I am developing a synchronizer between two databases (SQL Server and MySQL) with ElectronJS and Node.JS and everything is working fine, but I would like to execute the window.close() method to terminate the application when all tables are syncronized (which are done asynchronously within a for loop).
// I removed error and bank connection treatments because they are working
// Read json file that contains all tables and its columns (keys)
fs.readFile(ABSPATH + 'tables.json', 'utf8', async (err,json) => {
// Parse the content of the file into a JSON object
let vetor = JSON.parse(json)
// Foreach table
for (let i = 0; i < vetor.length; i++) {
// Read the table from SQL Server and save it falues into MySQL
await read(vetor[i].table,vetor[i].keys)
}
// Instead of closing, I'm just displaying this message on screen (for debugging)
document.body.innerHTML += "<h2>All data where inserted</h2>"
})
But as you can see, it is returning the final result before returning the functions, that is, they remain asynchronous:
Click here to see the image
I believe my error is at the time of saving the data in the following function because I tested it with console.log(), but I still can't make it synchronous:
con.connect(async err => {
// Begin MySQL Transaction
await con.beginTransaction(async err => {
// Clear the table
await con.query(`TRUNCATE TABLE ${table}`, err => {})
// Loop to insert all inputs into table
for (let i = 0; i < values.length; i++){
// Create and execute the query to input values into table
await con.query(createInsert(table,keys,values[0]), err => {})
}
// When all data are inputed, end Transaction
await con.commit(err => {
// Write in window that everything gonna allright
document.body.innerHTML += "<p>All data where successfully saved into " + table + ".</p>"
})
})
// End MySQL Transaction
})
Like georg had told me, the problem was that I was trying to await async functions, but the await only works with Promises.
I found the answer greetings to him and to this answer that I had received on StackOverflow in portuguese.
So, I just put my connection into a Promise, like this:
// Save datas into MySQL Database
function save(table, keys, values) {
return new Promise((res, rej) => {
// MSSQL returns a JSON object filled with informations that I don't want
// so I filter only what I want: the result of the query
values = values.recordset
// Start a new MySQL connection
let con = mysql.createConnection({
user: OUSER,
password: OPASS,
server: OHOST,
port: OPORT,
database: ODB
})
con.connect(err => {
if (err) {
alert(err)
window.close()
}
con.beginTransaction(err => {
// This function is just for DontRepeatYourself
rollBack(con, err, rej)
con.query(`TRUNCATE TABLE ${table}`, err => { rollBack(con, err, rej) })
con.query(createInsert(table,keys,values[0]), err => { rollBack(con, err, rej) })
con.commit(err => {
rollBack(con, err, rej)
document.body.innerHTML += `<p>All data where successfully registered into ${table}.</p>`
res()
})
})
})
})
}

Request inside a nested request loop to another server

I need to request X products from another server and I need to wait for that execution to finish before proceeding and saving the order in the database.
Let's say I receive via post an array of product Ids that I need to add to the order, e.g
JSON FILE:
{
"order_products":[1,2,3,4]
}
Here's a code sample:
//Express module
var router = require('express').Router();
//HTTP Request module
var client = require('request');
//Util that saves the URLs of the other databases
var productURL = require('../utils/product/productURL');
//Builds a product object given a JSON
var productBuilder = require('../utils/product/productBuilder');
router.post('/', req, res) {
//Instantiate a new order
var orderInstance = new order({
date: Date.now
});
//Query the products in the other server and add them to the order
req.body.order_products.forEach(id => {
client.get(productURL.HTTPS + id, { json: true }, (err, res, JSONProduct) => {
var product = productBuilder.build(JSONProduct);
orderInstance.order_products.push(product);
});
};
//Save the order in the database
orderInstance.save(....);
//Send response
res.status(201).json(orderInstance);
}
The problem here is that while the loop is still executing, the response is sent (201) and the orderInstance is saved without any product. If I console.log the products they only appear after the orderInstance is saved.
I've tried implementing callbacks to fix this issue, but with no success. I'd appreciate if anyone could lend me a hand here! Thanks in advance :smiley:(edited)
forEach runs synchronously - when the forEach ends, the client.get requests may have all been sent out, but the responses surely haven't come back yet. You need to convert each request into a Promise, and then call Promise.all on an array of those Promises. The Promise.all will resolve once all responses have come back. For example:
const allPromises = req.body.order_products.map(id => new Promise((resolve, reject) => {
client.get('productURL.HTTPS' + id, { json: true }, (err, res, JSONProduct) => {
if (err) reject (err);
else resolve(productBuilder.build(JSONProduct));
});
}));
Promise.all(allPromises)
.then((newProducts) => {
orderInstance.order_products.push(...newProducts);
res.status(201).json(orderInstance);
})
.catch((err) => {
// handle errors
});

How to add conditional checks over ORM (sequelizejs) queries?

Suppose i have a table gameData {gameId, currentBoardLayout}, a get request like www.chess.com/asd123 is sent over to the server, where asd123 is my game id, I need to catch this id (asd123 which is my gameId) and check for it in my table (gameData) and implement the following logic :
srv.get('/:id', (req, res) => {
if ( gameData.findAll({where: {gameId: req.params.id} )
{ // Game room found
return currentBoardLayout
}
else
{ error : Invalid game id }
})
How can I achieve this?
Thanks
You can use Sequelize's findById method.
srv.get('/:id', (req, res) => {
gameData.findById(req.params.id)
.then(result => {
res.send(result)
})
.catch(() => {
res.send({
error: 'Could not find ID'
})
})
})
Here's what is happening:
Sequelize's findById method will return a promise. If it successful, you will get your item from the database back. If the item cannot be found, the catch method will fire.
res.send is Express' way of sending data back to the client.
It is worth checking out the Sequelize docs:
Using models
Querying

Categories

Resources