Google App Script - Function Returning Undefined - javascript

I'm trying to call a function that gets a channel ID when given a Slack Workspace and channel name. I can get the correct result within the function, but when I try to call the function elsewhere, it is returning undefined.
Function to get the channel ID `
//GET CHANNEL ID FROM LIST OF ALL CHANNELS IN WORKSPACE
function getChannelID(workspaceName, pageLimit, channelName, nextCursor){
var channelListResponseURL = 'https://slack.com/api/conversations.list';
var payload = {
'limit': pageLimit,
'types': 'public_channel, private_channel',
'cursor' : nextCursor
};
var options = createURLargs(workspaceName, payload);
var channelListResponse = UrlFetchApp.fetch(channelListResponseURL, options);
var channelListJson = channelListResponse.getContentText();
var channelListData = JSON.parse(channelListJson);
//iterate through each channel in the returned JSON object and sets the channel ID for the one matching the channelName
for (var i in channelListData.channels){
if(channelListData.channels[i].name == channelName){
var channelID = channelListData.channels[i].id;
Logger.log('FOUND CHANNEL ID: '+ channelID);
return channelID;// IF CHANNEL ID FOUND, THEN EXIT getChannelID FUNCTION AND RETURN CHANNEL ID
}
}
// IF NO CHANNEL ID IS FOUND, THEN CHECK TO SEE IF PAGINATION IS IN EFFECT, UPDATE CURSOR, AND RERUN getChannelID FUNCTION
if (channelListData.response_metadata.next_cursor && channelListData.response_metadata.next_cursor != ""){
nextCursor = channelListData.response_metadata.next_cursor;
getChannelID(workspaceName, pageLimit, channelName, nextCursor);
} else {
// IF CHANNEL PAGINATION IS NOT IN EFFECT, OR REACHED LAST PAGE AND NO RESULT IS FOUND
return 'No Channel Found in Workspace';
}
}
`
I can clearly see the 'FOUND CHANNEL ID: CXXXXXX' string in the logger, so I'm sure it finds it properly.
But when I call this getChannelID from the main function, it is returning undefined.
var channelID = getChannelID(workspaceName, pagLimit, channelName, nextCursor);
Logger.log(channelID);
The weird thing is this seems to work when the JSON object from Slack isn't paginated, but when the results are returned paginated, I just seem to get undefined.
Any ideas why the result it's returning is undefined, even though it works in the function?

I think that in your recursive function, the value is not returned. So how about this modification?
From :
if (channelListData.response_metadata.next_cursor && channelListData.response_metadata.next_cursor != ""){
nextCursor = channelListData.response_metadata.next_cursor;
getChannelID(workspaceName, pageLimit, channelName, nextCursor);
} else {
// IF CHANNEL PAGINATION IS NOT IN EFFECT, OR REACHED LAST PAGE AND NO RESULT IS FOUND
return 'No Channel Found in Workspace';
}
To :
if (channelListData.response_metadata.next_cursor && channelListData.response_metadata.next_cursor != ""){
nextCursor = channelListData.response_metadata.next_cursor;
return getChannelID(workspaceName, pageLimit, channelName, nextCursor); // Modified
} else {
// IF CHANNEL PAGINATION IS NOT IN EFFECT, OR REACHED LAST PAGE AND NO RESULT IS FOUND
return 'No Channel Found in Workspace';
}
Note :
When channelListData.response_metadata.next_cursor && channelListData.response_metadata.next_cursor != "" is true, no value is returned. So I added return.
If this didn't work yet, please tell me. I would like to modify it.
Added :
In my understanding, when the recursive function is run, the process returns to the line which was run. In order to confirm this, I prepared 3 sample functions.
Function 1
function foo1(value) {
if (value == "") {
foo1("bar");
} else {
return "ok";
}
}
Function 2
function foo2(value) {
if (value == "") {
return foo2("bar");
} else {
return "ok";
}
}
Function 3
function foo3(value) {
if (value == "") {
foo3("bar");
}
return "ok";
}
When these functions is run by as follows,
var res1 = foo1("");
var res2 = foo2("");
var res3 = foo3("");
res1, res2 and res3 are undefined, ok and ok, respectively.

Related

How to use Array contains in two different array fields in firebase for flutter

I have a document with two fields, searchkeys1 and searchkeys2, I want my firebase query to check if a value I provided is present in searchkey1 and return, if not search searchkey2, my first attempt was to create a query with the value and first check searchkey1 and if the documents returned are empty, try searchkey2, my problem is I keep getting an error when I am trying to check if any documents were returned
"the getter 'documents' isn't defined for the type 'Stream<QuerySnapshot>' "
here is my code
startSearch(input) {
var docSnapshot = FirebaseFirestore.instance
.collection('items')
.where('searchkeys1', arrayContains: input.toString()).snapshots();
if (docSnapshot.documents.length == 0) {
var docSnapshot2 = FirebaseFirestore.instance
.collection('items')
.where('searchkeys2', arrayContains: input.toString()).snapshots();
return docSnapshot2;
} else if (docSnapshot.documents.length != 0) {
return docSnapshot;
}
You need to make your function async and use get insted of smnapshots:
startSearch(input) async {
var docSnapshot = await FirebaseFirestore.instance
.collection('items')
.where('searchkeys1', arrayContains: input.toString()).get();
if (docSnapshot.documents.length == 0) {
var docSnapshot2 = await FirebaseFirestore.instance
.collection('items')
.where('searchkeys2', arrayContains: input.toString()).get();
return docSnapshot2;
} else if (docSnapshot.documents.length != 0) {
return docSnapshot;
}
With get you get the data once as you want it. But with snapshots you get a listener for realtime chanegs.

Get and check a value from JSON read in NodeJS

I'm trying to check if a user exists (registered on a json file).
Unfortunately I don't find a valid solution in all Stack Overflow that gives me a simple "true" in a callback.
The version closest to a solution
Experiment V1 :
let userExist;
function check(){
console.log("CHECK!");
return userExist = true;
}
// check(); if this, return true... obvious.
//// check if user exist
server.readFileSync(filepath, 'utf8', (err, data) =>
{
let json = JSON.parse(data),
userlist = json.allusers;
for (let key in userlist)
{
if ( userlist[key].email == req.body.user_email )
{
console.log("FINDED EQUAL");
check(); // return undefined ???
}
}
});
console.log("userExist value : "+userExist);
differently formulated the debugs also appear, but "true" never returns.
note: yes, JSON is read correctly. If everything works inside the readfile, you immediately notice the same emails.
output: "undefined"
Log: total bypassed
Experiment V2 :
In this case (with asynchronous reading) it returns all the debugging (but the "true" remains undefined)
The problem with the asynchronous is that I have to wait for it to check to continue with the other functions.
//// check if user exist
server.readFile(filepath, 'utf8', (err, data) =>
{
let json = JSON.parse(data),
userlist = json.allusers;
for (let key in userlist)
{
if (/* json.allusers.hasOwnProperty(key) &&*/ userlist[key].email == req.body.user_email )
{
console.log("FINDED EQUAL");
check();
}
}
});
var userExist;
function check(userExist){
console.log("CHECK!");
return userExist=true;
}
console.log("userExist value : "+userExist+"");
server listening on: 8080
userExist value : undefined
CHECK!
FINDED EQUAL
Experiment V3 :
after the various suggestions I come to a compromise by using the syntax for the async functions.
This allowed to reach an ordered code, but despite this it is not possible to wait for the results and export them out of the same function (this is because node itself is asynchronous! Therefore it has already gone on!)
using a "message" variable to check if it could return an object I did so:
//simple output tester
var message;
// create a promise
let loopusers = new Promise( (resolve)=>{
server.readFile( filepath, 'utf8',
(err, data) => {
let json = JSON.parse(data),
userlist = json.allusers,
findedequal;
console.log("CHECK USERS IN DB...for "+userlist.length+" elements");
// loop all items
for (let key in userlist)
{
console.log("Analyzed key ::: "+key);
if ( userlist[key].email == req.body.user_email )
{
console.log("CHECK : user isn't free");
findedequal=true;
resolve(true); // return the result of promise
}
else if(key >= userlist.length-1 && !findedequal )
{
console.log("CHECK : User is free ;)");
resolve(false); // return the result of promise
}
}
// call the action
createuser();
});
});
// when promise finished --> start action
async function createuser(message)
{
let userExist = await loopusers;
console.log("userExist: "+userExist);
if(userExist)
{
message = { Server: "This user already exists, Try new e-mail..."};
}
else
{
message = { Server: "Registration user -> completed..."};
}
// return values
return message;
};
It is also possible to use the classic syntax via "then". For exemple:
//simple output tester
var message;
// create a promise
let loopusers = new Promise( (resolve)=>{
...
});
loopusers.then( (response)=>{
...
})
Then I realized that it was easy to simplify even more by calling the functions directly from the initial one:
var message;
// create a promise --> check json items
server.readFile( filepath, 'utf8',
(err, data) => {
let json = JSON.parse(data),
userlist = json.allusers,
findedequal;
console.log("CHECK USERS IN DB...for "+userlist.length+" elements");
for (let key in userlist)
{
console.log("Analyzed key ::: "+key);
if ( userlist[key].email == req.body.user_email )
{
console.log("CHECK : user isn't free");
findedequal=true;
createuser(true); // call direct function whit params true
}
else if(key >= userlist.length-1 && !findedequal )
{
console.log("CHECK : User is free ;)");
createuser(false); // call direct function whit params false
}
}
});
// start action
function createuser(userExist)
{
if(userExist)
{
message = { Server: "This user already exists, Try new e-mail..."};
}
else
{
message = { Server: "Registration user -> completed!"};
}
// return values
return message;
};
debugging is taken and written
the message is lost outside the aSync function
Experiment V4 Final! :
Finally, after many attempts the solution! (Yes... But know it's not Async)
If we allocate in a variable the reading becomes synchronous the whole model and we return to the simple one
let message,
file = server.readFileSync(filepath, 'utf8'), // read sync
json = JSON.parse(file), // now parse file
userlist = json.allusers, // get your target container object
userExist,
findedequal;
console.log("CHECK USERS IN DB...for "+userlist.length+" elements");
for (let key in userlist)
{
console.log("Analyzed key ::: "+key);
if ( userlist[key].email == req.body.user_email )
{
console.log("CHECK : finded equal value on key ["+key+"] - user isn't free");
findedequal=true;
userExist = true;
}
else if(key >= userlist.length-1 && !findedequal )
{
console.log("CHECK : User is free ;)");
userExist = false;
}
}
if(userExist)
{
console.log("└ EXIT TO CHECK --> Can't create user, function stop.");
message = { Server: "This user already exists, Try new e-mail..."};
}
else
{
console.log("└ Exit to check --> New user registration ...");
message = { Server: "Registration user -> completed!"};
}
}
return message;
Now:
It's all sync and all log is perfect
all var is checked
all return... return
** Final conclusions: **
Is it possible to retrieve an ASync variable in node?
As far as I understand so far ... no.
Node is async by its nature, therefore recovering information that is not saved and then recovered from a DB is left behind among the things to do, becoming unrecoverable if you use it as in this post.
However ... if the purpose is to make reading a file synchronous, the answer was simpler than expected.
A special thanks to: Barmar; Austin Leehealey; C.Gochev;
The problem is that you are calling console.log("userExist value : "+userExist+"");
too early. At the moment that you call that line, userExist is not defined yet. This is because the server.readFile() function requires a callback and that callback function is executed once it has read the file. However, reading files often take time and so the program keeps going. It executes console.log("userExist value : "+userExist+""); and then goes back to the callback function and defines userExist as true.
If you want more information on what callbacks are look at the link below. Callbacks are a defining feature of Nodejs and understanding them is essential to any Node website.
https://medium.com/better-programming/callbacks-in-node-js-how-why-when-ac293f0403ca
Try something like this.
let userExist;
function check(){
console.log("CHECK!");
return userExist = true;
}
// check(); if this, return true... obvious.
//// check if user exist
server.readFileSync(filepath, 'utf8', (err, data) =>
{
let json = JSON.parse(data),
userlist = json.allusers;
for (let key in userlist)
{
if ( userlist[key].email == req.body.user_email )
{
console.log("FINDED EQUAL");
check(); // return undefined ???
console.log("userExist value : "+userExist);
}
}
});

Skip to else if property is undefined

I have function that creates a team and puts data to database. Now I'm trying to check if team already exists, if it does exists then reply with message. I have problem with my if statement.
if (result[0].teamname == teamName)
When result[0].teamname is undefined it shows Cannot read property 'teamname' of undefined it ignores else and throws an error. How can I make so that does not ignore else?
Here is the function I use to create team.
function createTeam(teamName, members, message) {
teamName = teamName.replace("_", " ");
let insertTeam = `INSERT INTO teams (teamname) VALUES ('${teamName}');`;
db.select(`SELECT id_t, teamname FROM teams WHERE teamname = '${teamName}'`, function(err, result) {
if (err) {
throw err;
} else {
if (result[0].teamname == teamName) {
if (message.guild !== null) message.delete();
message.reply("this team already exists!");
} else {
db.query(insertTeam);
db.select(`SELECT id_t FROM teams WHERE teamname = '${teamName}'`, function(err, result) {
if (err) {
throw err;
} else {
for (let i = 0; i < members.length; i++) db.query(`INSERT INTO team_user (user, team) VALUES ('${members[i]}' , ${result[0].id_t})`);
}
});
if (message.guild !== null) message.delete();
let newTeam = new Discord.RichEmbed()
.setThumbnail("https://cdn.discordapp.com/emojis/542789472421675028.png?v=1")
.setColor("#15f153")
.addField("New team has been created!", `Team ${teamName} has been created with total of ${members.length} members!\nGood luck!`);
message.channel.send(newTeam);
}
}
});
What have I tried so far:
Checking if result[0].teamname is undefined
Checking if result length is not 0
try-catch statement
if (result[0] && result[0].teamname == teamName)
First of all you need to check if result[0] is not undefined
You need to short-circuit the condition. All this means is you want to first check that result exists before checking properties of result
So for example, your code should look like this:
if (result && result[0] && result[0].teamname == teamName) {
//Do something
}
If result is array with more then one value, then you need to iterate over every one of them, you can use filter array method for this:
var found = result.filter((row) => row.teamname == teamName);
if (found.length) {
}
You can also as #ThomasKleßen mention in comment check if result is not undefined:
var found = result && result.filter((row) => row.teamname == teamName).length;
if (found) {
}
You can always do a default value
if ((result || [{}])[0].teamname == teamName)
If the result is falsy, it will default to an array of an empty object, which will allow for the array access and dot notation to work, but the equality to fail.

Variable not accessing inside of function

ive made a function for my twitch bot. which when they input a command checks if they are already in the list. if they are not in the list it will add them to the list. The code below outputs this : [ undefined ]
[17:53] info: [#kong_plays] *<kng_bot>: 1
var wtpLength = [];
function lfg(user){
WTPLength = viewersWTP.length;
if (WTPLength !== 0) {
viewersWTP = viewersWTP - 1
while(WTPLength !== -1){
if(user === viewersWTP[WTPLength]){
console.log("Already in list")
client.action("kong_plays",user+" you cannot execute this command again until kong pulls a viewer to play with him!")
}else{
viewersWTP.push(user['display-name'])
console.log("Added into list")
client.action("kong_plays",viewersWTP)
}
}
}else{
viewersWTP.push(user['display-name'])
console.log(viewersWTP)
client.action("kong_plays","1"+viewersWTP)
}
}
Something like this may work for you. You are using variables that are undefined. It also looks as though you are not paying attention to the cases of the variables that you are defining.
var viewersWTP = []; // add this or define it elsewhere
function lfg(user){
var wtpLength = viewersWTP.length;
if (wtpLength !== 0) {
viewersWTP = viewersWTP - 1
while(wtpLength !== -1){
if(user === viewersWTP[wtpLength]){
console.log("Already in list")
client.action("kong_plays",user+" you cannot execute this command again until kong pulls a viewer to play with him!")
}else{
viewersWTP.push(user['display-name'])
console.log("Added into list")
client.action("kong_plays",viewersWTP)
}
}
}else{
viewersWTP.push(user['display-name'])
console.log(viewersWTP)
client.action("kong_plays","1"+viewersWTP)
}
}
Change the user['display-name'] into user. You passed that var throught the function

Azure mobile service - reading from two tables and return custom response object

I am writing Azure Mobile Service (AMS) API with JavaScript backend named customertickets and in the .get function I am attempting to read values from two tables in my AMS.
The two tables are 'User' and 'Ticket' and I am attempting to retrieve all tickets based on the passed parameter (phonenumber) and return some statistical data. Additionally, I am injecting a custom return value item.spname when looping through the tickets if the ticket satisfy a certain condition (item.parsedjsondata.SPId is not null or empty).
Here is the complete code (ctrl+F 'THIS DOES NOT WORK!'):
//Get ticket info by customer phonenumber
exports.get = function(request, response) {
var phonenumber = request.query.phonenumber;
var activeTicketsCounter = 0;
var completedTicketsCounter = 0;
var canceledTicketCounter = 0;
var needCustomerRatingTicketCounter = 0;
var includeCounterData = request.query.includeCounterData;
console.log("customertickets/get phonenumber: " + phonenumber);
request.service.tables.getTable('Ticket').read({
//SEE: http://stackoverflow.com/questions/24406110/how-to-get-system-properties-createdat-version-in-javascript-backend-of-azu
systemProperties: ['__createdAt', '__updatedAt'],
success: function(result) {
//No ticket is found
if (result.length === 0) {
console.log("customertickets/get: no ticket found");
response.send(statusCodes.NOT_FOUND, { message: "customertickets/get: no ticket is found" });
}
//return tickets after filtration based on the customer phonenumber
else {
console.log("customertickets/get: ticket found");
var filteredResults = [];
result.forEach(function(item) {
//only tickets with matched phonen number
if (JSON.parse(item.jsondata).customerPhonenumber == phonenumber) {
console.log(item);
//Adding parsed jsondata to item
item.parsedjsondata = JSON.parse(item.jsondata);
//Adding the name of the assigned spid; only if spid is not null ie. ticket is already assinged
if (item.parsedjsondata.SPId) {
console.log("SPID", item.parsedjsondata.SPId);
console.log("customerId", item.parsedjsondata.customerId);
//This works as expected
item.spid = item.parsedjsondata.SPId;
request.service.tables.getTable('User').where({ id: item.parsedjsondata.SPId.toString(), usertype: "200" }).read({
success: function(userResults) {
console.log('result', userResults[0]);
//Does not exist; return NOT FOUND as sp name!
if (userResults.length === 0) {
//This wroks fine and logs the expected result
console.log("customertickets/get: not SPname found", item.parsedjsondata.SPId);
//THIS DOES NOT WORK!
item.spname = "Service Provider Name Not Found";
}
//Record exists; return it
else {
//This wroks fine and logs the expected result
console.log("retrieved spname", JSON.parse(userResults[0].userjsondata).businessData.businessname.ar);
//THIS DOES NOT WORK!
item.spname = JSON.parse(userResults[0].userjsondata).businessData.businessname.ar;
}
}
});
}
//ActiveTicketsCounter
if (item.parsedjsondata.ticketStatus == "TicketStatus_ToBeAssigned"
|| item.parsedjsondata.ticketStatus == "TicketStatus_IsAssigned"
|| item.parsedjsondata.ticketStatus == "TicketStatus_InProgress"
|| item.parsedjsondata.ticketStatus == "TicketStatus_SPDisputed_CustomerNotReachable"
|| item.parsedjsondata.ticketStatus == "TicketStatus_SPDisputed_OutOfScope"
|| item.parsedjsondata.ticketStatus == "TicketStatus_SPDisputed_CustomerCanceled"
|| item.parsedjsondata.ticketStatus == "TicketStatus_SPDisputed_PriceDisagreement") {
activeTicketsCounter++;
}
//needCustomerRatingTicketCounter
if (item.parsedjsondata.ticketStatus == "TicketStatus_Completed_No_Customer_Rating") {
needCustomerRatingTicketCounter++;
}
//CompletedTicketsCounter
if (item.parsedjsondata.ticketStatus == "TicketStatus_Completed_And_Customer_Rated") {
completedTicketsCounter++;
}
//canceledTicketCounter
if (item.parsedjsondata.ticketStatus == "TicketStatus_CanceledByB8akAgent") {
canceledTicketCounter++;
}
//Testing: it works!
item.testing = "Testing Something!";
console.log("item.spname before push:", item.spname);
//pushing the found item to the list of results
filteredResults.push(item);
}
});
console.log("includeCounterData: " + includeCounterData);
if (includeCounterData == true) {
//After the loop, add the counters to the filteredresults to be returned
filteredResults.push({
activeTickets: activeTicketsCounter,
pendingCustomerRatingTickets: needCustomerRatingTicketCounter,
completedTickets: completedTicketsCounter,
canceledTickets: canceledTicketCounter
});
}
response.send(statusCodes.OK, filteredResults);
}
}
});
};
My main issue is that item.spname is never assigned a value and does not get returned in the response. I can see that the assigned value of item.spname which is JSON.parse(userResults[0].userjsondata).businessData.businessname.ar logs successfully in the AMS log but it does not get returned in the response.
The problem you have is that you're not waiting for the result of the many calls to
request.service.tables.getTable('User').where(...).read(...
to arrive before sending the response back to the client. Remember that almost everything in the node.js / JavaScript backend is asynchronous. When you call read on the User table, it won't wait for the result to arrive before executing the next statement - instead, it will queue the operation so that when the response is available, it will be executed.
To fix this you'll need to make all read calls to the users table, and only after you've got all the callbacks is when you can call response.send.

Categories