Not getting response in time when using geo.find() in node.js - 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);
}
);
});

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.

no resolve after paginated https request

I'm trying to get all of the paginated pages from a api that allows a max of 250 records pr call/page.
But I can't make it work a 100% - I get the data but it do not resolve the right way- i hangs.
I use https.request and I don't want to use fetch or any other kind fetching.
the code:
moreThan250(nextLink) {
return new Promise((resolve, reject) => {
try {
let body = []
options.path = "/admin/api/2022-07/" + nextLink
let time = parseInt(new Date().getTime() / 100000) // del med 10000 så filnavnet ikke skifter navn undervejs men skifter fra ca hver tredje min (burde være tid nok til at hente alle produkter)
console.log("moreThan250 time", time);
const req = https.request(options, (res) => {
res.on('data', (d) => {
body.push(d)
})
res.on("end", () => {
body = Buffer.concat(body).toString()
fs.appendFile("src/data/allProducts.json", body + ",", (e) => console.log(e))
const headerLink = res.headers.link
if (headerLink) {
const match = headerLink.match(/<[^;]+\/(\w+\.json[^;]+)>;\srel="next"/);
const nextLink = match ? match[1] : false;
if (nextLink) {
this.moreThan250(nextLink)
}
else {
console.log("moreThan250 end inside", body.length);
resolve()
}
} else {
resolve()
}
})
});
req.end()
} catch (error) {
console.log("moreThan250 error", error);
reject(false)
}
})
}
async function go(){
let tmp = await this.moreThan250(`products.json?limit=250`)
if(tmp) console.log("getAllProducts hentede moreThan250", tmp);
else console.log("no tmp");
}
go()
logs out "no tmp"
What I want is the collected data/body, so how do I return all the data to tmp (the appendFile got all the right data)

readFile synchronously nodejs

I am new to nodejs and just started learning. I need to read 5 json files and place them in an array. I have created 2 functions: readDirectory and processFile.
let transactionArray = [];
router.get('/', (req,res) => {
//joining path of directory
const directoryPath = path.join(__dirname, '../data');
readDirectory(directoryPath);
res.send(JSON.stringify(transactionArray))
})
readDirectory will get the dir and will read the filenames.
function readDirectory(directoryPath){
//passsing directoryPath and callback function
fs.readdir(directoryPath, function (err, files) {
//handling error
if (err) {
return console.log('Unable to scan directory: ' + err);
}
//listing all files using map
let fileSummary = files.map(file => {
//get the filename
let categoryName = ''
if (file.includes('category1')) {
categoryName = 'category1'
} else if (file.includes('category2')) {
categoryName = 'category2'
} else {
categoryName = 'Others'
}
// read the file
const filePath = directoryPath +'/'+ file
fs.readFile(filePath, 'utf8', (err, fileContents) => {
if (err) {
console.error(err)
return
}
try {
let data = JSON.parse(fileContents, categoryName)
processFile(data, categoryName);
} catch(err) {
console.error(err)
}
})
})
});
}
Then it will read the file using function processFile.
function processFile(data, categoryName)
{
let paymentSource = ''
if (categoryName == 'category1'){
paymentSource = categoryName +': '+ categoryName +' '+ data.currency_code
} else if (categoryName == 'category2') {
paymentSource = categoryName +': '+ data.extra.payer +'-'+ data.currency_code
} else {
paymentSource = 'Others'
}
let transactionDetails = new Transaction(
data.id,
data.description,
categoryName,
data.made_on,
data.amount,
data.currency_code,
paymentSource)
transactionArray.push(transactionDetails)
console.log(transactionArray);
}
The console log is something like this:
[{Transaction1}] [{Transaction1},{Transaction2}] [{Transaction1},{Transaction2},{Transaction3}]
but the result on the UI is only []
During debug, I noticed that it is not reading synchronously so I tried using readFileSync but it did not work. How can I read both functions synchronously so it will not give an empty array?
Do some playing around to understand what the fs functions do when they have callbacks, and when they're synchronous. From the code that you have we have make a few changes so that you don't have to use the synchronous functions from the file system library.
First of all you need to wait for all the asynchronous tasks to complete before returning response.
router.get('/', async (req, res) => {
// joining path of directory
const directoryPath = path.join(__dirname, '../data')
readDirectory(directoryPath).then(() => {
res.send(JSON.stringify(transactionArray))
}).catch(err => {
res.status(500).json(err)
})
})
Secondly, to keep the code as is as to teach you something about promises, lets wrap the first function in a promise.
function readDirectory (directoryPath) {
return new Promise((resolve, reject) => {
// passsing directoryPath and callback function
fs.readdir(directoryPath, function (err, files) {
// handling error
if (err) {
return console.log('Unable to scan directory: ' + err)
}
// listing all files using map
const fileSummary = Promise.all(
files.map(file => {
return new Promise((resolve, reject) => {
// get the filename
let categoryName = ''
if (file.includes('category1')) {
categoryName = 'category1'
} else if (file.includes('category2')) {
categoryName = 'category2'
} else {
categoryName = 'Others'
}
// read the file
const filePath = directoryPath + '/' + file
fs.readFile(filePath, 'utf8', (err, fileContents) => {
if (err) {
console.error(err)
reject(err)
}
try {
const data = JSON.parse(fileContents, categoryName)
processFile(data, categoryName).then(data => {
data()
})
} catch (err) {
console.error(err)
reject(err)
}
})
})
})
).then(() => {
resolve()
}).catch(err => {
reject(err)
})
})
})
}
Please refer to the bible (MDN) for javascript about promises -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
And finally wrap the processFile function in a promise
function processFile (data, categoryName) {
return new Promise((resolve, reject) => {
let paymentSource = ''
if (categoryName == 'category1') {
paymentSource = categoryName + ': ' + categoryName + ' ' + data.currency_code
} else if (categoryName == 'category2') {
paymentSource = categoryName + ': ' + data.extra.payer + '-' + data.currency_code
} else {
paymentSource = 'Others'
}
const transactionDetails = new Transaction(
data.id,
data.description,
categoryName,
data.made_on,
data.amount,
data.currency_code,
paymentSource)
transactionArray.push(transactionDetails)
console.log(transactionArray)
resolve()
})
}
What the heck am I doing? I'm just making your code execute asynchronous task, but wait for them to be completed before moving on. Promises are a way to handle this. You can easily pull this off with the FS synchronous functions, but this way you can learn about promises!

Why is Await not working in async function?

I am trying to use await in an async function. Hwoever, I am getting the error
SyntaxError: await is only valid in async function
I cant figure out where the problem is in the below code.
insertPayrollAllowance: async function(companyId, jobId, basicSalary, employeeId, payrollId) {
return new Promise((resolve, reject) => {
sqlQuery = "SELECT * from tblJobAllowances Where tblJobAllowances.companyId = '" + companyId + "' and tblJobAllowances.jobId = '" + jobId + "' and deleterec = 0 order by id"
db.executeQuery(sqlQuery, null, (err, result) => {
if (err) {
reject(err);
} else {
for (var i = 0; i < result.length; i++) {
var insStatus = false;
var allowanceId = result[i].allowanceId
var allowanceName = await this.getAllowanceName(companyId, allowanceId);
var amountType = result[i].typeOfAmount;
var amount = result[i].amount;
var amountCredited;
var taxable = result[i].taxable;
if ($.trim(amountType) == "FIXED AMT") {
amountCredited = parseFloat(amount.toString().replace(/,/g, ''));
} else if ($.trim(amountType) == "% Of Income") {
amountCredited = (parseFloat(basicSalary.toString().replace(/,/g, '')) / 100) * parseFloat(amount.toString().replace(/,/g, ''));
};
var info = {
companyId: companyId,
employeeId: employeeId,
payrollId: payrollId,
allowanceName: allowanceName,
amountType: amountType,
amount: amount,
amountCredited: amountCredited,
taxable: taxable
}
sqlQuery = "INSERT INTO tblPayrollAllowanceDetails SET ?"
db.executeQuery(sqlQuery, info, (err, result) => {
if (err) {
insStatus = false;
} else {
insStatus = true;
}
});
};
resolve(insStatus);
}
});
});
}
I will be glad if anyone could point out why Im getting this error. Any assistance will be highly appreciated.
The await is inside another function that's not async
db.executeQuery(sqlQuery, null, (err, result) => {
It's inside this arrow function (err, result) => {
so to fix it just add async like so:
db.executeQuery(sqlQuery, null, async (err, result) => {

How to keep my function alive while I iterate through all the documents in a collection?

I have around 100 documents under a collection and am trying to go through all of them to check if a field is greater than 0. If it is, decrement it, if it isn't move on to the next doc. The function however stops executing due to status code 200 somehow.
exports.decrementDaysLeft = functions.https.onRequest((req, res) => {
res.send(startDecrementing());
});
function startDecrementing() {
db.collection('PremiumUsers').get().then(snapshot => {
if (!snapshot.empty)
{
console.log("Query Size " + snapshot.size)
snapshot.forEach(doc => {
console.log("Checking for user " + doc.id);
decrementDaysLeftForUser(doc.id);
})
return 200;
}
}).catch(err => {
console.log(err);
return 400;
});
};
function decrementDaysLeftForUser(email) {
var userColl = db.collection('PremiumUsers/' + email + '/subscribedSubjects');
userColl.get().then(snapshot => {
if (!snapshot.empty) {
snapshot.forEach(doc => {
var num = Number(doc.data().daysLeft);
if (num > 0) {
console.log('Checking ' + doc.id);
doc.ref.update({
daysLeft: (num - 1).toString()
}).then(function () {
console.log("Decremented " + doc.id + " for " + email);
}).catch(err => {
log.console(err);
})
}
else {
console.log('Days left is zero ' + doc.data().daysLeft);
}
})
}
else {
console.log('No subjects');
}
})
};```
The response was sent before the decrementDaysLeftForUser() finishes its execution. You need to wait for it to finish the execution before sending out the response.
Using the await keyword makes sure it waits for the awaited function decrementDaysLeftForUser() to finish before continuing the execution of the current function startDecrementing(). Notes: await keyword can only be used inside async function. The code will look like this:
exports.decrementDaysLeft = functions.https.onRequest((req, res) => {
res.send(startDecrementing());
});
function startDecrementing() {
db.collection('PremiumUsers').get().then(async (snapshot) => {
if (!snapshot.empty)
{
console.log("Query Size " + snapshot.size)
for(let doc of snapshot) {
console.log("Checking for user " + doc.id);
await decrementDaysLeftForUser(doc.id);
}
return 200;
}
}).catch(err => {
console.log(err);
return 400;
});
};
async function decrementDaysLeftForUser(email) {
var userColl = db.collection('PremiumUsers/' + email + '/subscribedSubjects');
userColl.get().then(snapshot => {
if (!snapshot.empty) {
snapshot.forEach(doc => {
var num = Number(doc.data().daysLeft);
if (num > 0) {
console.log('Checking ' + doc.id);
doc.ref.update({
daysLeft: (num - 1).toString()
}).then(function () {
console.log("Decremented " + doc.id + " for " + email);
}).catch(err => {
log.console(err);
})
}
else {
console.log('Days left is zero ' + doc.data().daysLeft);
}
})
}
else {
console.log('No subjects');
}
})
};```
Hope this helps.

Resources