I am using for-loop to iterate thru sheets in a google spreadsheet and access specific cell within each sheet. I have a google spreadsheet with five sheets Sheet1, Sheet2,.. , Sheet5. The value if the cell that I am reading is Value1,..., Value5.
I hope to get results displayed as follow:
Sheet1
Value1
Sheet2
Value2
:
Sheet5
Value5
However I get:
Sheet1
Undefined
Sheet2
Undefined
:
Sheet5
Undefined
Value1
Value2
:
Value5.
I realize that I need to use async/await, but can't figure the right away with google.spreadsheet.get.
Thanks in advance for any guidance.
My code:
function getData (auth) {
var sheets = google.sheets('v4')
sheets.spreadsheets.get(
{
auth: auth,
spreadsheetId: sheet_id
},
(err, response) => {
if (err) console.log('The API returned an error: ' + err)
}
)
var no_sheets = response.data.sheets.length
for (var i = 0; i < no_sheets; i++) {
try {
console.log(response.data.sheets[i].properties.title)
var sheet_title = response.data.sheets[i].properties.title
var cell_value = getCellValue(auth, sheet_title)
console.log(cell_value)
} catch (err) {
console.log(err)
continue
}
}
}
function getCellValue (auth, sheet_title) {
sheets.spreadsheets.values.get(
{
auth: auth,
spreadsheetId: sheet_id,
range: sheet_title + '!A1:A1'
},
(err, response) => {
if (err) {
console.log('The API returned an error: ' + err)
return
}
var rows = response.data.values
if (rows.length === 0) {
console.log('No data found.')
} else {
for (var i = 0; i < rows.length; i++) {
var cell_value = rows[i]
}
console.log(cell_value)
return cell_value
}
}
)
}
If you want to use async/await instead of callbacks you can, because the googleapi returns a Promise. Those Promises are the foundation of async/await and were the goto before. If you use async/await or Promises your code will be much easier to read and understand.
So instead of calling:
sheets.spreadsheets.get({
auth: auth,
spreadsheetId: sheet_id
},
(err, response) => {
if (err) console.log('The API returned an error: ' + err)
});
you can call:
try {
const response = sheets.spreadsheets.get({
auth: auth,
spreadsheetId: sheet_id
});
}
catch(err) {
console.log('The API returned an error: ' + err);
}
Thing is that you can use the await keyword only in async functions. You can read more about async/await here.
Related
I have a sqlite3 database request in my main.js, that is triggered by button click in renderer.js.
The request reaches my main.js. However, I cannot manage to await the results from the database. The issue occurs already in main.js, so I'm stuck even before anything is passed back to the renderer.js.
I hope someone can tell me what I am missing.
Here is my code:
renderer.js
$(document).on('click','#mybtn',function(e){
let query = "SELECT id, name FROM table1"
// send (here is the issue)
window.api.send("db-query", query)
// (next step: receive, might be wrong but not yet my problem)
window.api.receive(channel="receive-db-data", (data) => {
console.log(data);
});
});
main.js
ipcMain.on(channel='db-query', async (e, query) => {
console.log('query received: ' + query);
let data = await db_request(query).then(
function(value) {
console.log('value: ' + value);
return value;
},
function(error) {
console.log('error fetching data from db on query:' + query);
}
)
console.log("response ready: " + data); //returns undefined if 'return value' is used (otherwise nothing)
// to send back to renderer.js later
e.sender.send("db-data", data)
})
let db_request = async (query) => {
let data = []
var sqlite3 = require('sqlite3').verbose();
var dbPath = require('path').resolve(__dirname, '../../Fin.db')
var db = new sqlite3.Database(dbPath)
db.serialize(function(){
db.each(query, function(err, row) {
console.log(row)
data.push({"id": row.id, "name": row.name})
});
});
db.close();
console.log('db_request:' + data)
return data
}
And this is how my terminal looks like:
query received: SELECT id, type, name FROM table1
db_request:
value:
response ready: undefined
{ id: 1, name: 'a' }
{ id: 2, name: 'b' }
{ id: 3, name: 'c' }
You have to convert db_request result to a Promise, and the promise will be resolved when all rows are pushed to the data. When you use the await keyword, there is no need to handle a promise with .then chain.
main.js will look like this:
const sqlite3 = require('sqlite3').verbose();
const dbPath = require('path').resolve(__dirname, '../../Fin.db')
ipcMain.on(channel='db-query', async (e, query) => {
console.log('query received: ' + query)
try {
const data = await db_request(query); // remove .then
console.log('value: ' + data)
// to send back to renderer.js later
e.sender.send("db-data", data)
} catch (error) {
console.log('error fetching data from db on query:' + query);
e.sender.send("db-data", []) // send empty data or error ???
}
})
let db_request = (query) => {
const db = new sqlite3.Database(dbPath)
return new Promise((resolve, reject) => { // return a promise
// I think you dont need serialize for this case
const data = []
db.each(query, (err, row) => {
console.log(err, row)
if (!err) {
data.push({"id": row.id, "name": row.name})
}
}, (error) => {
if (error) {
reject(error)
} else {
resolve(data)
}
});
})
}
i want to fetch data from api and execute for loop to store all response data in mysql database.then again fetch data from api with different request parameter but it does not wait to complete for loop and store data i have tried async/await but noting works
app.get("/api/garudaTx", (req, res) => {
let sql = "SELECT * FROM table_name ORDER BY id ";
let query = conn.query(sql, (err, results) => {
(async function () {
for (let i = 0; i < results.length; i++) {
const element = results[i];
console.log(element.userAddress);
console.log(element.id);
try {
let response = await axios.get(
`https://api.bscscan.com/apimodule=account&action=txlist&address=${element.userAddress}&startblock=1&endblock={blockNo}&sort=asc&apikey=`
);
let last = await (async function () {
console.log(response);
if (response.status != 200 || response.data.result.length == 0) {
let code = response.status.toString();
fs.appendFile("responseError.txt", code + " ", (err) => {
if (err) throw err;
console.log("The lyrics were updated!");
});
fs.appendFile(
"responseError.txt",
element.userAddress + " ",
(err) => {
if (err) throw err;
console.log("The lyrics were updated!");
}
);
}
let body = response.data;
console.log(response.data.result.length);
const promises = [];
for (var index = 0; index < response.data.result.length; index++) {
let data = {
blockNumber: body.result[index].blockNumber,
timeStamp: body.result[index].timeStamp,
hash: body.result[index].hash,
nonce: body.result[index].nonce,
blockHash: body.result[index].blockHash,
from_address: body.result[index].from,
contractAddress: body.result[index].contractAddress,
to_address: body.result[index].to,
value: body.result[index].value,
transactionIndex: body.result[index].transactionIndex,
gas: body.result[index].gas,
gasPrice: body.result[index].gasPrice,
gasUsed: body.result[index].gasUsed,
cumulativeGasUsed: body.result[index].cumulativeGasUsed,
confirmations: body.result[index].confirmations,
};
promises.push(
new Promise((resolve) => {
let sql = "INSERT INTO table_name SET ?";
resolve(
conn.query(sql, data, (err, results) => {
if (err) throw err;
console.log(
JSON.stringify({
status: 200,
error: null,
response: results,
})
);
})
);
})
);
}
await Promise.all(promises);
})();
} catch (err) {
console.log(err);
}
}
})();
});
res.send(JSON.stringify({ status: 200, error: null, response: "success" }));
});
i am executing a for to fetch user details from database then i execute api for each user and saved response data with loop but next api is hitting before saving all data in database it does not wait to complete nested for loop
Below is the piece of code i have written , to get the result but null in response
I am using selectObjectContent api to get the results with the simple SQL query
const bucket = 'myBucketname'
const key = 'file.json.gz'
const query = "SELECT * FROM s3object "
const params = {
Bucket: bucket,
Key: key,
ExpressionType: "SQL",
Expression: query,
InputSerialization: {
CompressionType: "GZIP",
JSON: {
Type: "LINES"
},
},
OutputSerialization: {
JSON: {
RecordDelimiter: ","
}
}
}
s3.selectObjectContent(params,(err, data) => {
if (err) {
console.log(data)
} else {
console.log(err)
}
})
I have found the solution to it. was logging error when getting successfull result/data , so corrected it below. Also i have found the way to read stream buffer data
s3.selectObjectContent(params,(err, data) => {
if (err) {
console.log(err)
} else {
console.log(data)
}
})
const eventStream = data.Payload;
// Read events as they are available
eventStream.on('data', (event) => {
if (event.Records) {
// event.Records.Payload is a buffer containing
// a single record, partial records, or multiple records
var records = event.Records.Payload.toString();
console.log( records )
} else if (event.Stats) {
console.log(`Processed ${event.Stats.Details.BytesProcessed} bytes`);
} else if (event.End) {
console.log('SelectObjectContent completed');
}
I am trying to use the node.js Google API to iterate over my email messages
const google = require('googleapis');
The problem is that I keep getting the same email messages and every response contains the exact same nextPageToken.
I also noticed that trying to control the maxResults parameter has no effect. I tried to add them to the options object and the query objects and it had no effect in either way.
function listThreads(auth, nextPageToken) {
const gmail = google.gmail('v1');
const query = {
auth : auth,
userId: 'me',
q: ""
};
const options = {maxResults: 20}
if (nextPageToken) {
query.pageToken = nextPageToken;
}
gmail.users.messages.list(query, options, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
const messages = response.messages;
if (messages.length === 0) {
console.log('No threads found.');
} else {
for (let i = 0; i < messages.length; i++) {
const message = messages[i];
gmail.users.messages.get({
auth : auth,
userId: 'me',
id : message.id
}, function(err, response) {
if (err) {
logger.error("Failed to get email", err);
} else {
const parser = new Parser();
parser.parse(response.payload, response.labelIds);
}
});
}
}
if (response.nextPageToken) {
listThreads(auth, response.nextPageToken);
}
});
}
What am I doing wrong?
I am using ssh2 nodejs module to connect to a UNIX application and run a script and it is successful.
Now i want to connect to multiple servers one by one and get the output and store it.
When i try using a for loop to pass the servers one by one from a json as input to the ssh2 the for loop completes much faster than the block which is supposed to get the output from the server.
This is also causing me handshake error.
Kindly help
Here is the code
inc_cron.schedule("*/20 * * * * *", function(id) {
});
//inc_cron.js
var cronFunction = function(inputStr) {
if(appNames['applications'].length>0){
for (i = 0; i < appNames["applications"].length; i++) {
getDataFromServer(appNames["applications"][i].Name,appNames["applications"][i].hostname, appNames["applications"][i].username, appNames["applications"][i].password, appNames["applications"][i].log_path, function(err, data) {
if(err) {
logger.info("Error is in cronFunction = ", err);
} else if(data) {
output_data +=data;
} ssh.close_second();
});
}
}
}
var getDataFromServer = function(Name,hostname, username, password, log_path, cb) {
ssh.close_second();
ssh.connect_second({
host: hostname,
username: username,
password: password
}, function(err) {
if(err) {
logger.error('Err: ', err);
} else {
ssh.sftp("",'grep -o "ERROR" '+log_path+'.log.'+yr+'-'+mnth+'-* | wc -l', function(err, data) {
cb(err, data);
}); } }); }
//connect.js
SSHConnection.prototype.sftp = function(type, path, cb) {
var self = this;
var log_data = '';
self.connection2.exec(path +' ' + type, { pty: true }, function(err, stream) {
if (err) {
logger.log('SECOND :: exec error: ' + err);
}
stream.on('end', function() {
self.connection2.end(); // close parent (and this) connection
}).on('data', function(data) {
logger.info(data.toString());
});
});
};
Without watch your code, be sure to handle correctly the async issue with ssh2... use a promise factory.
One way to do this is to use es7 async await. For this you have to rewrite your getDataFromServer function to return a promise:
var getDataFromServer = function(Name,hostname, username, password, log_path, cb) {
return new Promise(function(resolve,reject){
ssh.close_second();
sh.connect_second({
host: hostname,
username: username,
password: password
},function(err) {
if(err){
reject(err)
}else{
ssh.sftp("",'grep -o "ERROR" '+log_path+'.log.'+yr+'-'+mnth+'-* | wc -l', function(err, data) {
if(err){
reject(err)
}else{
resolve(data)
}
})
}
})
})
}
now you can rewrite your cron function to be an async function.
var cronFunction = async function(inputStr) {
if(appNames['applications'].length>0){
for (i = 0; i < appNames["applications"].length; i++) {
try{
output_data + = await getDataFromServer(appNames["applications"][i].Name,appNames["applications"][i].hostname, appNames["applications"][i].username, appNames["applications"][i].password, appNames["applications"][i].log_path)
}catch(err){
logger.info("Error is in cronFunction = ", err);
}
ssh.close_second();
}
}
}
async await enables you to write async code in syncronous coding style.
However async await is currently (node 7.*) hidden behind a flag (--harmony-async-await). this feature will be enable by default in the upcomming node release (8.0.0) in April 2017.
so to start your app you currently have to use
node --harmony-async-await yourapp.js
P.S.: This code is currently untested and most probably contains bugs .. but you get the idea.