fs.existsSync is not waiting for fs.readFile inside if - node.js

if (fs.existsSync('tmp/cache.txt')) {
fs.readFile("tmp/cache.txt", function (err, data) {
if (data != "" || data != "[]") {
jdata = JSON.parse(data);
if (
jdata[jdata.length - 1].substring(4, 8) ==
new Date().getFullYear() + 543
) {
year = new Date().getFullYear() + 542;
console.log("yes this year");
}
jdata.forEach(function (value, i) {
if (
value.substring(4, 8) ==
new Date().getFullYear() + 543
) {
countloveme--;
}
});
jdata.splice(countloveme);
}
});
}
my code is running but
code is finished before fs.readFile inside ifelse have finish
i don't how to add await in fs.readFile or anyway to this code is working

As written in the comments, it would be a better choice to use fs,readFileSync
And when you use Array.forEach() you are starting a new function that is running synchronously.
I've cleared your code maybe this can help you
if (fs.existsSync('tmp/cache.txt')) {
try {
const data = fs.readFileSync("tmp/cache.txt");
if (!data || data != "" || data != "[]")
throw new Error('tmp/cache.txt file is empty');
const jdata = JSON.parse(data);
// More clear to use variables in the if elses
const arg1 = jdata[jdata.length - 1].substring(4, 8)
const arg2 = new Date().getFullYear() + 543;
if (arg1 === arg2) {
// You don't use this date anywhere?
new Date().getFullYear() + 542;
console.log("yes this year");
}
for (let dataChunk of jdata) {
if (
dataChunk.substring(4, 8) ==
new Date().getFullYear() + 543
) {
countloveme--;
}
}
jdata.splice(countloveme);
} catch (error) {
console.error(error.message);
}
}

Related

Need Deep Understanding async/await on NodeJS

I've been trying to understand async/await and Task in NodeJS. I have implemented I need to update db when all process executed.
Below is code samples
const download = require('image-downloader');
const imageDownload = (imgurl) =>{
console.log("inside imageDownload ", new Date())
return new Promise(async(resolve) => {
let imgpath = '/mount/imageDownload/';
if (!fs.existsSync(imgpath)) {
fs.mkdirSync(imgpath, {
recursive: true
});
}
const options = {
url: imgurl,
dest: imgpath
};
console.log("before download image " + assetId + " ", new Date())
download.image(options)
.then(({ filename }) => {
resolve({"error":false, "url":filename});
})
.catch((err) => {
console.log(err);
resolve({"error":true,"message":err});
});
});
}
(async () => {
let downloadUrl1 = "";
let downloadUrl2 = "";
let downloadUrlFirst = await imageDownload("https://dummyimage.com/300.png/09f/fff");
if (typeof downloadUrlFirst.url != 'undefined' && downloadUrlFirst.url != null) {
downloadUrl1 = downloadUrlFirst.url;
}
let downloadUrlSecond = await imageDownload("https://dummyimage.com/300.png/09f/fff");
if (typeof downloadUrlSecond.url != 'undefined' && downloadUrlSecond.url != null) {
downloadUrl2 = downloadUrlSecond.url;
}
if (downloadUrl1 != '' || downloadUrl2 !='' ) {
let updateImagePayload = {}
if (portrait_mounturl != '') {
updateImagePayload.downloadUrl1 = downloadUrl1;
}
if (landscape_mounturl != '') {
updateImagePayload.downloadUrl2 = downloadUrl2;
}
updateImagePayload.modified_date_time = new Date().toISOString();
db.collection("images").findOneAndUpdate({_id:ObjectId(assetId)}, { $set: updateImagePayload }, (err, update) => {
if (err) {
resolve({"error":true,"message": err});
} else {
let resolveStatus = false;
let resolveMessage = "Successfully updated image";
resolve({"error":resolveStatus,"message":resolveMessage});
}
});
}
})();
I need to update if both has async proccess completed.
Note: Image will be optional. Means either 1 image or both
Getting High Memory and CPU utilization
Any help understanding this would be much appreciated.

Loop is not waiting for query to be executed in node js

I am using node-querybuilder module for executing queries. I need to loop query in loop.
dbConfig.getDB() returns connection and why loop is not waiting for the query to execute
firstHalf and secondHalf always A and A..loop is not waiting for query to be executed.
I am very new to node-querybuilder module.using async and await doesn't make any difference
dbConfig.getDB().query(`SELECT id, full_name, email,mobile from frms WHERE status = ? AND email IS NOT NULL`, ['1'], async (err, response) => {
if (err) {
console.log(err);
}
else if (response && response.length > 0) {
var curr = new Date;
var firstday = new Date(curr.setDate(curr.getDate() - curr.getDay() - 6));
var weekArr = [firstday];
for (let j = 1; j < 6; j++) {
var nextday = new Date(curr.setDate(firstday.getDate() + j));
weekArr.push(nextday);
}
// console.log(weekArr);
let dayWiseAttendanceArr = [];
for (let i = 0; i < response.length; i++) {
let frmWiseObj = {};
frmWiseObj.basic_details = { "id": response[i].id, "name": response[i].full_name, "email": response[i].email, "mobile": response[i].mobile };
frmWiseObj.attendance_details = [];
for (let k = 0; k < weekArr.length; k++) {
let inDate = weekArr[k].toISOString().split('T')[0];
let dateWiseObj = {};
dateWiseObj.date = inDate;
let firstHalf = "A";
let secondHalf = "A";
let query = `SELECT DATE_FORMAT(in_date,'%Y-%m-%d') as date,ifnull(in_date,'') as punch_in,ifnull(out_date,'') as punch_out FROM punching_detail where DATE_FORMAT(in_date,'%Y-%m-%d') = '${inDate}' and punching_detail.frm_id='${response[i].id}'`;
dbConfig.getDB().query(query, async (punch_err, punch_response) => {
if (punch_err) {
console.log(punch_err);
} else if (punch_response && punch_response.length > 0) {
let punch_in = punch_response[0].punch_in;
let punch_out = punch_response[0].punch_out;
if (punch_in <= (inDate + " 10:40:00") && punch_out >= (inDate + " 19:00:00")) {
firstHalf = "P";
secondHalf = "P";
} else if (punch_in <= (inDate + " 10:40:00") && punch_out <= (inDate + " 19:00:00") && punch_out >= (inDate + " 14:30:00")) {
firstHalf = "P";
secondHalf = "A";
} else if (punch_in >= (inDate + " 10:40:00") && punch_in <= (inDate + " 14:30:00") && punch_out >= (inDate + " 19:00:00")) {
firstHalf = "A";
secondHalf = "P";
} else if (punch_in >= (inDate + " 10:40:00") && punch_in <= (inDate + " 14:30:00") && punch_in <= (inDate + " 19:00:00")) {
var hours = Math.abs(punch_out - punch_in) / (60 * 60 * 1000);
if (hours >= 4.5) {
firstHalf = "P";
secondHalf = "A";
} else {
firstHalf = "P";
secondHalf = "P";
}
} else {
firstHalf = "A";
secondHalf = "A";
}
} else {
let query = `SELECT leave_type,start_day, end_day,DATE_FORMAT(start_date,'%Y-%m-%d') as date,DATE_FORMAT(end_date,'%Y-%m-%d') as end_date FROM leave_mgt where (DATE_FORMAT(end_date,'%Y-%m-%d') <= '${inDate}}' AND DATE_FORMAT(start_date,'%Y-%m-%d') <= '${inDate}}') and frm_id='${response[i].id}' and status = '1'`;
await dbConfig.getDB().query(query, async (leave_err, leave_response) => {
if (leave_err) {
console.log(leave_err);
} else if (leave_response && leave_response.length > 0) {
const element = leave_response[0];
if (element.end_date != '0000-00-00') {
if (element.start_date == inDate) {
if (element.start_day == 2) {
firstHalf = 'L';
secondHalf = 'L';
} else if (element.start_day == 0) {
firstHalf = 'L';
} else if (element.start_day == 1) {
secondHalf = 'L';
}
} else if (element.end_date == inDate) {
if (element.end_day == 2) {
firstHalf = 'L';
secondHalf = 'L';
} else if (element.end_day == 0) {
firstHalf = 'L';
} else if (element.end_day == 1) {
secondHalf = 'L';
}
} else {
firstHalf = 'L';
secondHalf = 'L';
}
}
}
});
}
dateWiseObj.first_half = firstHalf;
dateWiseObj.second_half = secondHalf;
frmWiseObj.attendance_details.push(dateWiseObj);
});
}
dayWiseAttendanceArr.push(frmWiseObj);
}
}
else {
console.log("No Active frms found");
}
});
}```
Am not familiar with node-querybuilder but on this line:
await dbConfig.getDB().query(query, async (leave_err, leave_response) => {/* some code */ });
since the query method takes in a callback, it probably does not return a promise (you could confirm this by looking at the documentation/source code). This means using await here will not make your code wait for query to complete (since await has to be followed by a promise for it to have any effect).
If the library you're using doesn't use promises, maybe try promisifying the query method, so that you can await it. Promisifying can be done using something built-in like util/promisify or manually by creating a wrapper function (something like below):
function queryAsPromise(sql, parameters) {
return new Promise((resolve, reject) => {
dbConfig.getDB().query(sql, parameters, (err, response) => {
if (err) {
return reject(err);
}
resolve(response);
});
});
}
You can then await whatever queryAsPromise resolves to, like below:
async function main() {
const response = await queryAsPromise(
`SELECT id, full_name, email,mobile from frms WHERE status = ? AND email IS NOT NULL`,
[1]
);
// Rest of your code...
}
Why don't you just use a promisified helper function to execute your queries and return the result?
// DB setup
const dbConfig = {
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASS,
database: process.env.DATABASE_NAME,
port: process.env.DATABASE_PORT,
}
// Connection handler
const handleConnection = () => {
return new Promise((resolve, reject) => {
const client = mysql.createConnection(dbConfig); // Recreate the connection, since the old one cannot be reused.
client.connect(function onConnect(err) { // The server is either down
if (err) { // or restarting (takes a while sometimes).
console.log('error when connecting to db:', err);
setTimeout(handleConnection, 10000); // We introduce a delay before attempting to reconnect,
return;
} // to avoid a hot loop, and to allow our node script to
console.log('Database connected.');
resolve(client);
});
// process asynchronous requests in the meantime.
// If you're also serving http, display a 503 error.
client.on('error', function onError(err) {
console.log('db error', err);
if (err.code == 'PROTOCOL_CONNECTION_LOST') { // Connection to the MySQL server is usually
handleConnection(); // lost due to either server restart, or a
} else { // connnection idle timeout (the wait_timeout
reject(err); // server variable configures this)
}
});
})
}
// Query handler
export.mySql = (query, values = null) => {
return new Promise(async (resolve, reject) => {
try {
const client = await handleConnection();
let db = client;
db.query(query, values, (err, result, fields) => {
if (!err) {
resolve(result);
client.end();
console.log('Query executed');
return;
}
client.end();
throw err;
});
} catch (error) {
reject(err);
}
});
}
So whenever you call the mySql function; it connects to DB, executes the query, and returns the result.
Usage:
const { mySql } = require('./db.js');
const result = await mySql(`SELECT id, full_name, email,mobile from frms WHERE status = ? AND email IS NOT NULL`, ['1']);
console.log(result);

Spreadsheet not saving when using process.exit()

I'm using google spreadsheet and when I use process.exit() to stop my script It doesn't save the changes that I made to the spreadsheet. The problem is in the "row.save()" part, row.id row.status and row.tr_link do update. If I take out the process.exit() everything works fine.
async function accessSpreadsheet() {
const document = new GoogleSpreadsheet(thespreadsheetkey)
await promisify(document.useServiceAccountAuth)(credentials)
const info = await promisify(document.getInfo)()
const sheet = info.worksheets[0]
const rows = await promisify(sheet.getRows)()
var counter = 0
rows.forEach(async (row) => {
if (row.status == "") {
let data = await getCompanyID(row.email)
if (!data) {
await createCompany(row)
console.log(
`...`
)
//sendEmail(company)
} else
console.error(
`...`
)
row.status = "sent"
row.save()
} else if (row.status == "sent" && row.id == "") {
let data = await getCompanyID(row.email)
if (!data) {
console.error(
`...`
)
}
try {
row.id = data.id
row.tr_link = `...`
row.save()
console.log(
`...`
)
} catch (err) {
console.error(err, err.stack)
}
}
counter++
if (counter == rows.length) {
console.log("...")
return process.exit(0)
}
})
}

Why on my NodeJS+Express REST API a promise calling my function fails while the same promise with setTimeout works?

I have a NodeJS+Express REST API method executing reverse geocoding (using Google's Maps API).
I'm trying to solve it with Promises but the 'then' is getting executed before my function returns with the answers from Google.
When testing the same code just calling a setTimeout, it works as expected. Please see comments in the code (simplify version).
app.get('/api/v1/events', verifyToken, async (req, res) => {
await db.poolPromise.then(pool => {
return pool.request()
.input('UserId', db.sql.UniqueIdentifier, res.authData.userId)
.input('DateFrom', db.sql.DateTime2(7), req.query.dateFrom)
.input('DateTill', db.sql.DateTime2(7), req.query.dateTo)
.output('UserIdAuthorized', db.sql.Bit)
.execute('sp')
}).then(result => {
let output = (result.output || {})
if (!output.UserIdAuthorized) {
res.sendStatus(403)
}
else if (result.recordset.length > 0) {
(new Promise( (resolve) => {
//resolve(123) // this one works as expected
//setTimeout(resolve, 3000, 'temp success') // this one works as expected
// *** this one get passed and the following then is being executed before it answers ***
resolve( getAddress_TEST(result.recordset) )
// **************************************************************************************
})).then(function (value) {
res.json(
{
meta: { count: 10 }, //this is just a sample
result: value // *** this one fails with undefined ***
})
})
} else {
res.sendStatus(404)
}
}).catch(err => {
res.sendStatus(500)
console.error(err)
})
});
const nodeGeocoder_options = {
provider: 'google',
apiKey: process.env.GOOGLE_API_KEY
}
async function getAddress_TEST(recordset) {
//sample recordset for debugging - as you dont have my database
recordset = [{'eventId':14205556,'Lat':54.57767,'Lon':-2.4920483},{'eventId':14205558,'Lat':54.57767,'Lon':-2.492048},{'eventId':14205579,'Lat':53.416908,'Lon':-2.952071},{'eventId':14205588,'Lat':52.644448,'Lon':-1.153185},{'eventId':14205601,'Lat':52.29174,'Lon':-1.532283},{'eventId':14205645,'Lat':52.644448,'Lon':-1.153185},{'eventId':14205801,'Lat':53.68687,'Lon':-1.498708},{'eventId':14206041,'Lat':51.471521,'Lon':-0.2038033},{'eventId':14206049,'Lat':51.471521,'Lon':-0.2038033},{'eventId':14206072,'Lat':51.471521,'Lon':-0.2038033}]
let geocoder = nodeGeocoder(nodeGeocoder_options)
let ps = []
for (var i = 0, length = recordset.length; i < length; i++) {
if (i == 0 || !(i > 0
&& recordset[i - 1].Lat == recordset[i].Lat
&& recordset[i - 1].Lon == recordset[i].Lon)) {
ps.push(new Promise(function (resolve) {
resolve(reverseGeocode(geocoder, recordset[i].Lat, recordset[i].Lon))
}))
} else {
ps.push('-')
}
}
await Promise.all(ps)
.then(function (values) {
for (var i = 0, length = values.length; i < length; i++) {
if (values[i] != '-') {
recordset[i].locationAddress = values[i]
} else {
recordset[i].locationAddress = recordset[i - 1].locationAddress
}
}
}).then(function () {
recordset.forEach(function (v) {
delete v.Lat
delete v.Lon
});
console.log(recordset)
return recordset
})
};
async function reverseGeocode(geocoder, lat, lon) {
let address = '+'
if (lat != 0 && lon != 0) {
await geocoder.reverse({ lat: lat, lon: lon })
.then(res => {
address = res[0].formattedAddress
})
.catch(err => {
console.error(err)
});
}
return address
};
I'm sure it is something simple that I'm missing here...
The basic problem is that your getAddress_TEST function returns a promise that fulfills with nothing (undefined), because it does not contain a return statement. The return recordset is in a then() callback, from where it affects the promise resolution of the awaited promise, but that result is thrown away.
If you want to use async/await, you should get rid of any new Promise and then calls:
app.get('/api/v1/events', verifyToken, async (req, res) => {
try {
const pool = await db.poolPromise
const result = await pool.request()
.input('UserId', db.sql.UniqueIdentifier, res.authData.userId)
.input('DateFrom', db.sql.DateTime2(7), req.query.dateFrom)
.input('DateTill', db.sql.DateTime2(7), req.query.dateTo)
.output('UserIdAuthorized', db.sql.Bit)
.execute('sp')
let output = (result.output || {})
if (!output.UserIdAuthorized) {
res.sendStatus(403)
} else if (result.recordset.length > 0) {
const value = await getAddress_TEST(result.recordset)
res.json({
meta: { count: 10 }, //this is just a sample
result: value
})
} else {
res.sendStatus(404)
}
} catch(err) {
res.sendStatus(500)
console.error(err)
}
});
const nodeGeocoder_options = {
provider: 'google',
apiKey: process.env.GOOGLE_API_KEY
}
async function getAddress_TEST(recordset) {
const geocoder = nodeGeocoder(nodeGeocoder_options)
const ps = recordset.map((record, i) => {
if (i == 0 || !(i > 0
&& recordset[i - 1].Lat == record.Lat
&& recordset[i - 1].Lon == recordLon)) {
return reverseGeocode(geocoder, recordset[i].Lat, recordset[i].Lon))
} else {
return '-'
}
});
const values = await Promise.all(ps)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
for (var i = 0, length = values.length; i < length; i++) {
if (values[i] != '-') {
recordset[i].locationAddress = values[i]
} else {
recordset[i].locationAddress = recordset[i - 1].locationAddress
}
}
recordset.forEach(function (v) {
delete v.Lat
delete v.Lon
});
console.log(recordset)
return recordset
// ^^^^^^^^^^^^^^^^
}
async function reverseGeocode(geocoder, lat, lon) {
if (lat != 0 && lon != 0) {
const res = await geocoder.reverse({ lat: lat, lon: lon })
return res[0].formattedAddress
}
return '+'
}

Not getting response in time when using geo.find() in node.js

I have tried to get the response from below code:-
let latlongdata;
if (userInfo.address != "" && userInfo.country != "") {
let add = userInfo.address + "," + userInfo.country;
geo.find(add, function(err, res) {
latlongdata = res[0].location.lat;
console.log("Inside output", res[0].location.lat); // Got response
});
console.log("Outside output", getletlong); // No response
}
}
On consoling "Inside output" I got response,
On consoling "Outside output" I got no response
I also tried using async await, below is the code:-
if (userInfo.address != "" && userInfo.country != "") {
add = userInfo.address + "," + userInfo.country;
[err, data] = await to(geo.find(add));
console.log("output", data);
console.log("error", err);
}
Finally I got the response when I used setTimeOut()
let latlongdata;
if (userInfo.address != "" && userInfo.country != "") {
add = userInfo.address + "," + userInfo.country;
geo.find(add, function(err, res) {
if (res) {
userInfo.latitude = res[0].location.lat;
}
});
}
userInfo.role_id = 2;
setTimeout(async () => {
[err, user] = await to(User.create(userInfo));
}, 300);
But I think this is not the right way, also I think this will not work for me in every case, please can anyone tell me what am I doing wrong in the first two approaches.
I used.:- "google-geocoder": "^0.2.1"
I have done some R&D and find the below solution
let add = userInfo.address + "," + userInfo.country;
return new Promise((resolve, reject) => {
geo.find(
"India",
(err, res) => {
if (res) {
resolve(res);
}
if (err) {
reject(err);
}
},
err => {
reject(err);
}
);
});

Resources