Spreadsheet not saving when using process.exit() - node.js

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)
}
})
}

Related

While we are create list and list columns using "pnp/sp". Why some of the columns are not created in one go?

While we are create list and list columns using pnp/sp. Why some of the columns are not created in one go? We need to run again then it will created. Please help me to resolve this issue.
I have used SPFx solution with react and "pnp/sp". Please refer below configuration for the same.
node 14.15.4
#microsoft/generator-sharepoint#1.14.0
gulp#4.0.2
npm#6.14.10
yo#4.3.0
#pnp/sp#2.11.0
Please refer below code snippet for the same.
import { sp } from '#pnp/sp';
import "#pnp/sp/webs";
import "#pnp/sp/lists";
import "#pnp/sp/items";
import "#pnp/sp/fields";
import "#pnp/sp/views";
import { UrlFieldFormatType } from "#pnp/sp/fields";
export const trainingsList = async () => {
try {
const listEnsureResult = await sp.web.lists.ensure("Trainings", "Trainings", 100, false, { Hidden: false });
if (listEnsureResult.created) {
return listEnsureResult;
}
} catch (error) {
console.log("Error in Trainings List", error);
}
}
export const trainingsFields = async () => {
const courseList = await sp.web.lists.getByTitle("Course")();
try {
await sp.web.lists.getByTitle("Trainings").fields.select("*").get().then(async (res) => {
let listData = [];
res.forEach(ele => {
listData.push(ele.InternalName);
});
if (listData.indexOf("VideoUrl") == -1) {
setTimeout(() => {
sp.web.lists.getByTitle("Trainings").fields.addUrl("VideoUrl", UrlFieldFormatType.Hyperlink).then(() => {
sp.web.lists.getByTitle("Trainings").defaultView.fields.add("VideoUrl");
})
}, 5000);
}
if (listData.indexOf("Walkthrough") == -1) {
sp.web.lists.getByTitle("Trainings").fields.addMultilineText("Walkthrough").then(() => {
sp.web.lists.getByTitle("Trainings").defaultView.fields.add("Walkthrough");
});
}
if (listData.indexOf("Status") == -1) {
sp.web.lists.getByTitle("Trainings").fields.addBoolean("Status").then(() => {
sp.web.lists.getByTitle("Trainings").defaultView.fields.add("Status");
});
}
if (listData.indexOf("TrainingDuration") == -1) {
sp.web.lists.getByTitle("Trainings").fields.addNumber("TrainingDuration").then(() => {
sp.web.lists.getByTitle("Trainings").defaultView.fields.add("TrainingDuration");
});
}
if (listData.indexOf("Course") == -1) {
sp.web.lists.getByTitle("Trainings").fields.addLookup("Course", courseList.Id, "Title").then(() => {
sp.web.lists.getByTitle("Trainings").defaultView.fields.add("Course");
});
}
await sp.web.lists.getByTitle("Trainings").fields.select("*").get().then(async (resListData) => {
let listColumnData = [];
resListData.forEach(ele => {
listColumnData.push(ele.InternalName);
});
console.log("listColumnData...", listColumnData);
if (listColumnData.indexOf("VideoUrl") != -1 && listColumnData.indexOf("Walkthrough") != -1 && listColumnData.indexOf("Status") != -1 && listColumnData.indexOf("TrainingDuration") != -1 && listColumnData.indexOf("Course") != -1) {
console.log("Inside IF.....");
}
else {
console.log("Inside ELSE.....");
await trainingsFields();
}
}).catch((err) => {
console.log("Error in trainings fields creation", err);
});
console.log("Trainings fields created successfully!");
}).catch((err) => {
console.log("Error in Trainings fields", err);
});
} catch (error) {
console.log("Error in Trainings fields", error);
}
}
You need to use await with add functions, otherwise your function may terminate before all fields are created. In general, I would avoid mixing await with .then for simplicity. Consider something like:
if (listData.indexOf("Walkthrough") == -1) {
await sp.web.lists.getByTitle("Trainings").fields.addMultilineText("Walkthrough");
await sp.web.lists.getByTitle("Trainings").defaultView.fields.add("Walkthrough");
}
if (listData.indexOf("Status") == -1) {
await sp.web.lists.getByTitle("Trainings").fields.addBoolean("Status");
await sp.web.lists.getByTitle("Trainings").defaultView.fields.add("Status");
}
Normally, you should get a linter (or compiler) error or warning when you try to call an asynchronous function without waiting for it to terminate in some way (i.e. without await or .then or .catch), i.e. "shooting in the air", but this may depend on the linter settings, as far as I remember.
TLDR: replace all foo().then(result => ..) with const result = await foo() and you should be fine.
Another thing, there may be a much more efficient way to create fields not just in "one go" but in "one call", if you used batches, for example.

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.

fs.existsSync is not waiting for fs.readFile inside if

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);
}
}

function returns undefined discord.js

I'm writing my own discord bot and i have a function that should return a youtubelink, but everytime i get undefined. here is the code of the bot, it is written in discord.js/node.js
for example i'm in my discord talk and i write "!play allan becker faded" i only get an undefined in the embed message, i also tried to console.log the returned string, but its laso undefinedEmbed message
const Discord = require('discord.js')
const fs = require('fs')
const ytdl = require('ytdl-core')
const ffmpeg = require('ffmpeg')
const { debug, Console } = require('console')
const config = JSON.parse(fs.readFileSync('config.json', 'utf8'))
const ytapi3 = config.GoogleApiYT3
const search = require('youtube-search')
var client = new Discord.Client()
//setting status
client.on('ready', () => {
console.log("Logged in as", client.user.username, "...")
client.user.setPresence({
status: config.status,
activity: {
name: config.activity,
type: 'STREAMING',
url: config.streamingURL
}
})
})
//musicbot
client.on('message', async message => {
if(message.author.bot) return // test if bot has written this message
if(!message.channel.id == config.botcommandsChannelID) return //test if message is in botcommands channel
if(!message.content.startsWith(config.prefix)) return // test if prefix is used
const args = message.content.substring(config.prefix.length).split(" ") // split arguments into args[]-list and cut the prefix out
const voiceChannel = message.member.voice.channel
//test if user has permissions to use command
if(config.UseDJRole == "true") {
if(message.member.roles.cache.has(config.DJroleID) || message.member.roles.cache.has(config.ModeratorRoleID) || message.member.user.id == config.owner){
}else{
return sendEmbed(message.channel, config.ErrorColor, "Error", config.NoPermissionsToUseThisCommand)
}
}
if(!voiceChannel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_404) //testing if user is in voiceChannel
if(message.content.startsWith(config.prefix + config.PlayCommand)){ //Play-case
const permission = voiceChannel.permissionsFor(message.client.user)
if(!permission.has('CONNECT')) sendEmbed(message.channel, config.ErrorColor, "Error", config.NoPermissionsToJoinVC)
if(!permission.has('SPEAK')) sendEmbed(message.channel, config.ErrorColor, "Error", config.NoPermissionsToSpeakInVC)
var vidURL = new String("nothing");
//get link "vidURL"
if(args.length >= 2){
if(ytdl.validateURL(args[1])){
vidURL = args[1]
} else{
args.shift()
const vidSearchLink = args.join(' ')
try{
vidURL = searchOnYT(vidSearchLink, message.channel, args)
}catch(error){
return console.log(error)
}
}
}else {
return sendEmbed(message.channel, config.ErrorColor, "Error", config.NoArgs)
}
if(client.connection == null){
voiceChannel.join()
//play
sendEmbed(message.channel, config.MusicEmbedColorHEX, "Playing", vidURL)
} else{
if(voiceChannel.id != client.connection.voice.channel.id){
sendEmbed(message.channel, config.ErrorColor, "Error", config.AllreadyUsed + client.connection.voice.channel.name)
} else{
//play
sendEmbed(message.channel, config.MusicEmbedColorHEX, "Playing", vidURL)
}
}
}else if(message.content.startsWith(config.prefix + config.StopCommand) || message.content.startsWith(config.prefix + config.LeaveCommand)){
if(voiceChannel == client.voice.channel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_400) //test if you are in one voice channel with the bot
voiceChannel.leave()
if(message.member.voice.connection) message.guild.voice.disconnect()
}else if(message.content.startsWith(config.prefix + config.PauseCommand)){
if(voiceChannel == client.voice.channel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_400) //test if you are in one voice channel with the bot
//pause music
}else if(message.content.startsWith(config.prefix + config.ResumeCommand)){
if(voiceChannel == client.voice.channel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_400) //test if you are in one voice channel with the bot
//resume music
}else if(message.content.startsWith(config.prefix + config.SkipCommand)){
if(voiceChannel == client.voice.channel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_400) //test if you are in one voice channel with the bot
//skip
}else if(message.content.startsWith(config.prefix + config.QueueCommand)){
if(voiceChannel == client.voice.channel) return sendEmbed(message.channel, config.ErrorColor, "Error", config.InvalidVoiceChannel_400)//test if you are in one voice channel with the bot
//show queue
}
})
function sendEmbed(_channel, _Color, _Title, _Description, _URL){
const embedMessage = new Discord.MessageEmbed()
.setColor(_Color)
.setTitle(_Title)
.setDescription(_Description)
.setURL(_URL);
_channel.send(embedMessage)
}
function searchOnYT(searchstring, _channel){
var opts = {
maxResults: 1,
key: config.GoogleApiYT3,
type: 'video'
}
search(searchstring, opts, function(err, results) {
if(err) return console.log(err);
if(results){
const r = results[0]
return new String(r.link)
}else{
return sendEmbed(_channel, config.ErrorColor, "Error", NoResultsFound, searchstring)
}
})
}
client.login(config.token)
As you mentioned in your comment, your searchOnYT() function should only return a value once it gets a result. Otherwise, vidURL will always be undefined. You can use a Promise in combination with async/await to achieve this. Here's an example, in just the parts of the code that need to be changed to do this.
In your message handler:
try{
vidURL = await searchOnYT(vidSearchLink, message.channel, args);
} catch(error){
return console.log(error)
}
In your searchOnYT() function:
function searchOnYT(searchstring, _channel){
var opts = {
maxResults: 1,
key: config.GoogleApiYT3,
type: 'video'
}
return new Promise((resolve, reject) => {
search(searchstring, opts, function(err, results) {
if(err) reject(err);
if(results) {
const r = results[0]
resolve(new String(r.link))
}
else {
sendEmbed(_channel, config.ErrorColor, "Error", NoResultsFound, searchstring);
reject("No results found");
}
})
});
}
Now that searchOnYT() returns a Promise, this ensures that the function will only return a value once search() finishes executing. Using a callback would also have worked to achieve this, but promises are a much neater way of waiting before returning a value (and promises work very nicely with async/await, and your message handler luckily already uses async).

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