I'm learning NodeJS a bit to do some automation scripts, but I'm having a problem that I don't know how to solve.
Using google spreadsheet API and "promisify-node" package, I'm requesting some data from an spreadsheet, and trying to return part of the data to be used on another js file.
file: spreadsheet.js
const getProductsConfiguration = async(auth) =>
{
const sheets = google.sheets('v4');
const getValues = promisify(sheets.spreadsheets.values.get);
await getValues({
auth: auth,
spreadsheetId: utils.getSpreadsheedId(config.spreadsheet.configSpreadsheedUrl),
range: `${config.spreadsheet.configTabName}!A8:C1000`,
})
.then(function (response) {
var productsConfiguration = [];
for(var value in response.values)
{
if(response.values[value].length === 0) continue;
var productConfig = {
"productName": response.values[value][0],
"spreadsheetId": response.values[value][1],
"filterId": response.values[value][2]
};
productsConfiguration.push(productConfig);
}
console.log(productsConfiguration);
return productsConfiguration;
})
.catch(function (error){console.log(error); return false;});
};
app.js:
productsConfig = await spreadsheet.getProductsConfiguration(sheetAuth);
console.log(productsConfig);
this console.log is returning "undefined", but the console.log inside "spreadsheet.js" is returning the correct data.
What can I do to solve? thanks
You can just do const values = await getValues({...}).No need to put a then after it since the promise resolves to the values when you use await in front of a function that returns a promise.
const getProductsConfiguration = async(auth) => {
const sheets = google.sheets('v4');
const getValues = promisify(sheets.spreadsheets.values.get);
let values
try{
values = await getValues({
auth: auth,
spreadsheetId: utils.getSpreadsheedId(config.spreadsheet.configSpreadsheedUrl),
range: `${config.spreadsheet.configTabName}!A8:C1000`,
})
}catch(e){
console.log(error)
}
var productsConfiguration = [];
if(values){
for(var value in values) {
if(values[value].length === 0) continue;
var productConfig = {
"productName": values[value][0],
"spreadsheetId": values[value][1],
"filterId": values[value][2]
};
productsConfiguration.push(productConfig);
}
}
console.log(productsConfiguration);
return productsConfiguration
};
Hope this helps !
Related
I am trying to get data from an api using axios.
I am first getting the token, and then using the token to make the request. Since there is a limit on how much information can be responded, I have to use a while loop to get all the data and store it all to an empty array.
However, I am getting a bunch of 'undefined', I read other similar articles online with regard to this return, and most of them is because of "no return", but since I am using a while loop, where can I return the data?
const getDailySales = async (req, res) => {
try {
const res_token = await axios.post(
`https://cysms.wuuxiang.com/api/auth/accesstoken?appid=${process.env.TCSL_APPID}&accessid=${process.env.TCSL_ACCESSID}&response_type=token`
);
const token = res_token.data.access_token;
var list = [];
var pageTotal = true;
var pageNo = 1;
while (pageTotal) {
var salesData = await axios.post(
`https://cysms.wuuxiang.com/api/datatransfer/getserialdata?centerId=${process.env.TCSL_CENTERID}&settleDate=2022-09-30&pageNo=${pageNo}&pageSize=20&shopId=12345`
{},
{
headers: {
access_token: `${token}`,
accessid: `${process.env.TCSL_ACCESSID}`,
granttype: "client",
},
}
);
list.push(salesData);
console.log(salesData.data.data.billList.shop_name);
if (salesData.data.data.pageInfo.pageTotal !== pageNo) {
pageNo += 1;
} else {
pageTotal = false;
}
}
} catch (error) {
console.log(error);
}
};
Above implementation would work.
Return list just before catch and after ending of the while loop
} else {
pageTotal = false;
}
}
return list;
} catch (error) {
console.log(error);
}
};
Few suggestions
Use let/const instead of var.
Can elaborate more error handling
return list like this:
return res.status(200).json({list});
I try to get specific documents from MongoDB with Node.js and insert them into array.
const getStockComments = async (req) => {
const stockname = req.params.stockName;
var comments = [];
var data = [];
const stock = await stockModel.findOne({ name: stockname });
comments = stock.comments;
comments.forEach(async (commentId) => {
const comm = await commentModel.findOne({ _id: commentId });
data.push(comm);
console.log(data); // This returns the data in loops, because its inside a loop.
});
console.log(data); // This not returns the data and i don't know why.
return data;
};
The first console.log(data) returns the same data a lot of times because its inside a loop.
But the second console.log(data) dosen't returns the data at all.
What I'm doing wrong?
Instead of using loop , you can use $in operator to simplify things .
const getStockComments = async (req) => {
const stockname = req.params.stockName;
var comments = [];
var data = [];
const stock = await stockModel.findOne({ name: stockname });
comments = stock.comments;
commentModel.find({ _id: { $in: comments } }, (err, comments) => {
data = comments;
});
console.log(data);
return data;
};
The getURL() function creates an array of scraped URLs from the original URL. getSubURL() then loops through that array and scrapes all of those pages' URLs. Currently, this code outputs just fine to the console, but I don't know how to wait for my data to resolve so I can push all gathered data to a single array. Currently, when I try and return sites and then push to array, it only pushes the last value. I believe it's a promise.all(map) situation, but I don't know how to write one correctly without getting an error. Ideally, my completed scrape could be called in another function. Please take a look if you can
const cheerio = require('cheerio');
const axios = require('axios');
let URL = 'https://toscrape.com';
const getURLS = async () => {
try {
const res = await axios.get(URL);
const data = res.data;
const $ = cheerio.load(data);
const urlQueue = [];
$("a[href^='http']").each((i, elem) => {
const link = $(elem).attr('href');
if (urlQueue.indexOf(link) === -1) {
urlQueue.push(link);
}
});
return urlQueue;
} catch (err) {
console.log(`Error fetching and parsing data: `, err);
}
};
const getSubURLs = async () => {
let urls = await getURLS();
try {
//loop through each url in array
for (const url of urls) {
//fetch all html from the current url
const res = await axios.get(url);
const data = res.data;
const $ = cheerio.load(data);
//create object and push that url into that object
let sites = {};
sites.url = url;
let links = [];
//scrape all links and save in links array
$("a[href^='/']").each((i, elem) => {
const link = $(elem).attr('href');
if (links.indexOf(link) === -1) {
links.push(link);
}
//save scraped data in object
sites.links = links;
});
// returns list of {url:'url', links:[link1,link2,link3]}
console.log(sites);
}
} catch (err) {
console.log(`Error fetching and parsing data: `, err);
}
};
Don't think this is a Promise related issue at heart.
You'll need to collect your sites into an array that is initialized outside the loop. Then when getSubURLs() resolves, it will resolve to your array:
const getSubURLs = async() => {
let urls = await getURLS();
let siteList = [];
try {
for (const url of urls) {
// :
// :
// :
siteList.push(sites);
}
} catch (err) {
console.log(`Error fetching and parsing data: `, err);
}
return siteList; // array of objects
};
getSubURLs().then(console.log);
Here is my code snippet for parsing application data:
async function parseApplication(data: Application) {
const fieldGroupValues = {};
for (const group of Object.keys(data.mappedFieldGroupValues)) {
const groupValue = data.mappedFieldGroupValues[group];
for (const fieldName of Object.keys(groupValue.mappedFieldValues)) {
const { fieldValue } = groupValue.mappedFieldValues[fieldName];
}
return fieldGroupValues;
}
But I receive data as Promise object, how can I retrieve data from Promise?
In you example you are combining both of await and .then(), I would use only one of them.
Preferably await as the following:
try {
const dict = await getDictionaryByKey(fieldValue.value.entityDefinitionCode);
const dictItem = dict.find((item) => fieldValue.value.entityId === item.code);
acc[fieldName] = dictItem ? dictItem.text : fieldValue.value.entityId;
} catch (err) {
acc[fieldName] = fieldValue.value.entityId;
}
I am using following NodeJS module for getting onvif device in the network https://github.com/futomi/node-onvif, and which works fine.
But using below code the list of device found is always empty. I checked the getDeviceData function and which is getting the device and print data.
But using below code the line console.log(JSON.stringify(list)); execute before all scan process completed. How can I fix it.
async function getDeviceData(info){
var device = new onvif.OnvifDevice({
xaddr: info.xaddrs[0],
user : 'admin',
pass : '123456'
});
await device.init();
var dev_info = device.getInformation();
var rtsp_url = device.getUdpStreamUrl();
var data = {"Manufacturer":dev_info.Manufacturer,"Model":dev_info.Model};
console.log(data); // this print last
return data;
}
const onvif = require('node-onvif');
onvif.startProbe().then((device_info_list) => {
var list = [];
device_info_list.forEach((info) => {
var data = getDeviceData(info)
list.push(data);
});
console.log(JSON.stringify(list)); // this print first
}).catch((error) => {
console.error(error);
});
Here is what you want:
You need to use await to wait the promise to resolve with the data.
onvif.startProbe().then(async (device_info_list) => {
var list = [];
await Promise.all(device_info_list.map(async(info) => {
var data = await getDeviceData(info)
list.push(data);
}));
console.log(JSON.stringify(list)); // this print first
}).catch((error) => {
console.error(error);
});
The data const in the first function returns a promise so would have yo await that. So this should work:
async function getDeviceData(info) {
const device = new onvif.OnvifDevice({
xaddr: info.xaddrs[0],
user: 'admin',
pass: '123456',
});
await device.init();
const dev_info = device.getInformation();
const rtsp_url = device.getUdpStreamUrl();
const data = { Manufacturer: dev_info.Manufacturer, Model: dev_info.Model };
await Promise.resolve(data);
console.log(data); // this print last
return data;
}
onvif
.startProbe()
.then(device_info_list => {
const list = [];
device_info_list.forEach(async info => {
const data = await getDeviceData(info);
await Promise.resolve(list.push(data));
});
console.log(JSON.stringify(list)); // this print first
})
.catch(error => {
console.error(error);
});