cannot read the property of undefined - mysql

I am coding a server-side app in node JS and I am using a database in MySQL.
I get "TypeError: Cannot read property 'activated' of undefined"
The request I do should say "empty set" when I do it manually in the MySQL terminal.
When I try to use it in my code an I input and invalid discord_key, it returns an error, but I want it to return just a false alarm so I can catch it and use that info.
function checkKey(key) {
var activated = "";
var sqlcheck = "SELECT activated from authentification where discord_ key = ?";
console.log("in function");
DB.query(sqlcheck, [key], function (err, result) {
if (err) throw (err);
activated = result[0].activated;
});
if (!activated) {
console.log("null");
return ("NULL");
} else {
console.log("used");
return ("used");
}
}
I should get :
that request sends an empty set, so the key doesn't exist.
thank you for your help!

In case no result you can write this:
if (err) throw (err);
activated = result.length ? result[0].activated : false;
That will return false in case of no result.

The Error
The error is telling you that a variable you are using is undefined. It tells you this because you attempt to read a property from an undefined variable.
You mentioned result is an empty array. This means that any index you attempt to access returns undefined. For example:
let result = []
console.log(result[0] === undefined) // prints true
And in javascript, if you try and access a property of undefined, you get your error. Continuing our example:
result[0].activated // Throws error: Cannot read property 'activated' of undefined.
Since there is no guarentee that result[0] has a value, you should make sure it is not undefined before accessing it's properties. As #NipunChawla shows, one way is to check the array has a length (i.e at lease one value):
if (result.length) { // Does result have values?
activated = result[0].activated
} else {
activated = false
}
Better yet, if you know you are working with result[0] only, check whether it is defined directly:
if (result[0]) { // Does result[0] have a value?
activated = result[0].activated
} else {
activated = false
}
You are still left with the possibility that result[0].activated does not exist. Meaning activated would be undefined.
if (result[0] && result[0].activated) { // ... and does the first value
// contain the property activated?
activated = result[0].activated
} else {
activated = false
}
So all together now:
DB.query(sqlcheck, [key], function (err, result) {
if (err) throw (err);
if (result[0] && result[0].activated) {
activated = result[0].activated
} else {
activated = false
}
})
Async Callbacks
To fix !activated in the second if statement always being true, you should look into how callbacks work. Basically DB.query goes off and does its thing. When it is done, it will execute the function you provided it as a callback. The order of execution looks something like this:
Call DB.query to send a request to your database
Continue execution of your script. i.e check if (!activated) { ...
DB.query has now finished and calls your callback, assigning activated = result[0].activated. i.e function(err, result)
A quick way you could fix this would be like so:
function checkKey(key) {
var activated = "";
var sqlcheck = "SELECT activated from authentification where discord_ key = ?";
console.log("in function");
DB.query(sqlcheck, [key], function (err, result) {
if (err) throw (err);
if (result[0] && result[0].activated) {
activated = result[0].activated
} else {
activated = false
}
doSomethingWithResult(activated)
});
}
function doStuffWithResult(activated) {
if (!activated) {
console.log("null");
// Do your !activated stuff
} else {
console.log("used");
// Do your activated stuff
}
}
See this question for more info.

Related

object keys are undefined in if conditional, but inside the if statement I can access it

As the title states, I have a variable which is a javascript object, i'm comparing it with another js object by stringifying them. The problem is that the variable is completely accessible without calling the keys, so these
if(JSON.stringify(response) == JSON.stringify(lastcmd))
if(JSON.stringify(response.id) == JSON.stringify(lastcmd))
work perfectly fine, but accessing lastcmd's id key will cause it to throw undefined.
if(JSON.stringify(response) == JSON.stringify(lastcmd.id))
full code link here
Edit: Here's the JSON
{ "id" : "001", "app": "msgbox", "contents": { "title": "Newpaste", "message": "I'm a edited paste!" } }
Edit2: Here's the code on the post
const { BrowserWindow, app, dialog, ClientRequest } = require("electron");
const axios = require("axios");
const url = require("url");
let win = null;
let lastcmd;
function grabCurrentInstructions(fetchurl) {
return axios
.get(fetchurl)
.then(response => {
// handle success
//console.log(response.data);
return response.data;
})
.catch(function(error) {
// handle error
console.log(error);
});
}
function boot() {
//console.log(process.type);
win = new BrowserWindow({
resizable: true,
show: false,
frame: false
});
win.loadURL(`file://${__dirname}/index.html`);
//Loop everything in here every 10 seconds
var requestLoop = setInterval(getLoop, 4000);
function getLoop() {
grabCurrentInstructions("https://pastebin.com/raw/i9cYsAt1").then(
response => {
//console.log(typeof lastcmd);
//console.log(typeof response);
if (JSON.stringify(response.app) == JSON.stringify(lastcmd.app)) {
console.log(lastcmd.app);
clearInterval(requestLoop);
requestLoop = setInterval(getLoop, 4000);
} else {
lastcmd = response;
switch (response.app) {
case "msgbox":
dialog.showMessageBox(response.contents);
//console.log(lastcmd);
clearInterval(requestLoop);
requestLoop = setInterval(getLoop, 1000);
}
}
}
);
}
}
app.on("ready", boot);
And here's the error:
(node:7036) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'id' of undefined
at grabCurrentInstructions.then.response (C:\Users\The Meme Machine\Desktop\nodejsprojects\electronrat\index.js:42:64)
at process._tickCallback (internal/process/next_tick.js:68:7)
Thanks to user str I saw that my lastcmd was undefined when I ran the comparison the first time, this would break it and thereby loop the same error over and over, by addding
grabCurrentInstructions("https://pastebin.com/raw/i9cYsAt1").then(
response => {
lastcmd = response;
}
);
below this line
win.loadURL(`file://${__dirname}/index.html`);
I made sure that the last command sent while the app was offline wouldn't be executed on launch and fixing my problem at the same time!

Break a Bluebird .each() process

I'm converting from Async to Bluebird and can't figure out how to break a loop
Here's what I'm trying to achieve:
Loop through an array of data.
For each item, check if it exists on DB.
Add one item to the DB (first item that doesn't exist), and exit the .each() loop.
Any help will be highly appreciated.
Bluebird does not have a built in function for that type of operation and it's a little bit difficult to fit into the promise iteration model because iterators return a single value (a promise) which doesn't really give you the opportunity to communicate back both success/error and stop iteration.
Use Rejection to Stop Iteration
You could use Promise.each(), but you'd have to use a coded rejection in order to stop the iteration like this:
var data = [...];
Promise.each(data, function(item, index, length) {
return checkIfItemExists(item).then(function(exists) {
if (!exists) {
return addItemToDb(item).then(function() {
// successfully added item to DB
// lets reject now to stop the iteration
// but reject with a custom signature that can be discerned from an actual error
throw {code: "success", index: index};
});
}
})
}).then(function() {
// finished the iteration, but nothing was added to the DB
}, function(err) {
if (typeof err === "object" && err.code === "success") {
// success
} else {
// some sort of error here
}
});
This structure could be put into a reusable function/method if you have to use it regularly. You just have to adopt a convention for a rejected promise that really just meant to stop the iteration successfully rather than an actual error.
This does seem like an interesting and not all that uncommon need, but I haven't seen any particular defined structure with Promises for handling this type of issue.
If it feels like overloading a reject as in the above scenario is too much of a hack (which it sort of does), then you could write your own iteration method that uses a resolved value convention to tell the iterator when to stop:
Custom Iteration
Promise.eachStop = function(array, fn) {
var index = 0;
return new Promise(function(resolve, reject) {
function next() {
if (index < array.length) {
// chain next promise
fn(array[index], index, array.length).then(function(result) {
if (typeof result === "object" && result.stopIteration === true) {
// stopped after processing index item
resolve(index);
} else {
// do next iteration
++index;
next();
}
}, reject);
} else {
// finished iteration without stopping
resolve(null);
}
}
// start the iteration
next();
});
}
Here if the iterator resolves with a value that is an object has has a property stopIteration: true, then the iterator will stop.
The final promise will reject if there's an error anywhere and will resolve with a value of null if the iterator finished and never stopped or with a number that is the index where the iteration was stopped.
You would use that like this:
Promise.eachStop(data, function(item, index, length) {
return checkIfItemExists(item).then(function(exists) {
if (!exists) {
return addItemToDb(item).then(function() {
// return special coded object that has stopIteration: true
// to tell the iteration engine to stop
return {stopIteration: true};
});
}
})
}).then(function(result) {
if (result === null) {
// finished the iteration, but nothing was added to the DB
} else {
// added result item to the database and then stopped further processing
}
}, function(err) {
// error
});
Flag Variable That Tells Iterator Whether to Skip Its Work
In thinking about this some more, I came up with another way to do this by allowing the Promise.each() iteration to run to completion, but setting a higher scoped variable that tells your iterator when it should skip its work:
var data = [...];
// set property to indicate whether we're done or not
data.done = false;
Promise.each(data, function(item, index, length) {
if (!data.done) {
return checkIfItemExists(item).then(function(exists) {
if (!exists) {
return addItemToDb(item).then(function() {
data.done = true;
});
}
})
}
}).then(function() {
// finished
}, function(err) {
// error
});

Comparing user input to some fields in an array of JSON objects

I have a webserver with JSON data in it. This is what my data looks like
[
{
iduser: 1,
username: "joe",
password: "****"
},
{
iduser: 2,
username: "gina",
password: "****"
}
]
In my app I take some user input and wish to compare it to the username and password field. Here is where I check the data
.service('LoginService', function ($q, $http) {
return {
loginUser: function (name, pw) {
var deferred = $q.defer();
var promise = deferred.promise;
var user_data = $http.get("http://<my ip address>:<port>/login");
user_data.then(function ($scope, result) {
$scope.user = result.data;
})
for (var x in $scope.user) {
if (name == x.username && pw == x.password) {
deferred.resolve('Welcome ' + name + '!');
} else {
deferred.reject('Wrong credentials.');
}
}
promise.success = function (fn) {
promise.then(fn);
return promise;
}
promise.error = function (fn) {
promise.then(null, fn);
return promise;
}
return promise;
}
}
})
I am still learning angularJS and I know this is not a secure way to check the data I just want this loop to work.
My understanding of what I have here is that $scope.user holds my JSON data. Then the data is cycled through with the for loop and the user input name is compared to the field username of each iteration. But this is not the case as I am getting a fail every time.
I'm almost certain its a syntax error, but I don't know JavaScript or AngularJS well enough to find the problem. Any help is really appreciated, Thanks.
Edit 1
After what Nujabes said I made some changes since I don't need $scope.
//previous code the same
user_data.then(function (result) {
var user = result.data;
})
for (var x in user) {
if (name == x.username && pw == x.password) {
//prior code the same
I don't think var can hold the data and thats why I'm still getting errors. I think it should be in an array.
I think your syntax error is that you omit $scope.
You should inject $scope service to this line:
.service('LoginService',function($q,$http,$scope){ ...
});
And this code :
user_data.then(function ($scope, result) {
$scope.user = result.data;
});
Omit the $scope.
->
user_data.then(function (result) {
$scope.user = result.data;
});
like this.
Give it a try.
I hope it work.
(However, why do you want to use $scope service in your 'service'?
I think, defining local value and returning some method is a better choice.
and you use the $scope service in your 'controller'.)
$scope.user you are trying to loop through is array right ?
using (for/in) will store the key in the variable x which is in your case the index of each element (0,1,2,..) , to loop through arrays use (for/of) like this :
for (var value of array)
this will give you the values ...

How to pass errors conditions

In web app development I would like a consistent way to catch and report error conditions. For example, a database update routine may detect a variety of error conditions and ideally I would like the application to capture them and report gracefully. The code below din't work because retdiag is undefined when error is thrown...
function saveData(app,e) {
var db ;
var retdiag = "";
var lock = LockService.getPublicLock();
lock.waitLock(30000);
try {
// e.parameters has all the data fields from form
// re obtain the data to be updated
db = databaseLib.getDb();
var result = db.query({table: 'serviceUser',"idx":e.parameter.id});
if (result.getSize() !== 1) {
throw ("DB error - service user " + e.parameter.id);
}
//should be one & only one
retdiag = 'Save Data Finished Ok';
}
catch (ex) {
retdiag= ex.message // undefined!
}
finally {
lock.releaseLock();
return retdiag;
}
}
Is there a good or best practice for this is GAS?
To have a full error object, with message and stacktrace you have to build one, and not just throw a string. e.g. throw new Error("DB error ...");
Now, a more "consistent" way I usually implement is to wrap all my client-side calls into a function that will treat any errors for me. e.g.
function wrapper_(f,args) {
try {
return f.apply(this,args);
} catch(err) {
;//log error here or send an email to yourself, etc
throw err.message || err; //re-throw the message, so the client-side knows an error happend
}
}
//real client side called functions get wrapped like this (just examples)
function fileSelected(file,type) { return wrapper_(fileSelected_,[file,type]); }
function loadSettings(id) { return wrapper_(loadSettings_,[id]); }
function fileSelected_(file,type) {
; //do your thing
}
function loadSettings_(id) {
; //just examples
throw new Error("DB error ...");
}

Why won't my req.flash work?

Here's a Node.js function. It works, in the sense that bad JSON data is kicked out, but it also flashes the message that it failed. Why?
// Create document
app.post('/documents.:format?', loadUser, function(req, res) {
/////////////////////////added by adam
//tests to see if the inputed text is valid JSON data
data = req.body.d.data;
console.log("///////////" + data);
try {
type = JSON.parse(data);
console.log(type);
} catch (ex) {
console.log("bad json: "+data);
req.flash('Nope', 'Invalid JSON');
res.redirect('/documents');
return;
}
var d = new Document(req.body.d);
d.user_id = req.currentUser.id;
d.save(function() {
switch (req.params.format) {
case 'json':
res.send(d.toObject());
break;
default:
req.flash('info', 'Document created');
res.redirect('/documents');
}
});
The catch block contains both the error message and the 'bad JSON' logger, so they will always occur at the same time, due to the block scope.