I got a nodejs app built like this:
app.get('/customer/:ent_cust_id', function (req, res, next) {
var query = 'Select * from entcustinfo where ent_cust_id = ' + req.params.ent_cust_id;
console.log('Select * from entcustinfo where ent_cust_id =' + req.params.ent_cust_id);
client.execute(query, function (err, result) {
if (err) return next (err);
var row = result.rows[0];
//Response
res.json({ent_cust_id: req.params.ent_cust_id, name: row.get('offers')});
});
});
but it causes node to shut down like this when the results of the array come back empty...
[root#ip-10-205-116-141 cassapi]# /usr/local/bin/node app.js
Example app listening at http://0.0.0.0:3030
Select * from entcustinfo where ent_cust_id =1106667844
events.js:87
throw er; // Unhandled 'error' event
^
TypeError: Cannot read property 'get' of undefined
at /home/ec2-user/cassapi/app.js:16:14
at readCallback (/home/ec2-user/cassapi/node_modules/cassandra-driver/lib/request-handler.js:195:5)
at Connection.invokeCallback (/home/ec2-user/cassapi/node_modules/cassandra-driver/lib/connection.js:567:5)
at Connection.handleResult (/home/ec2-user/cassapi/node_modules/cassandra-driver/lib/connection.js:507:8)
at ResultEmitter.emit (events.js:120:17)
at ResultEmitter.each (/home/ec2-user/cassapi/node_modules/cassandra-driver/lib/streams.js:437:17)
at ResultEmitter._write (/home/ec2-user/cassapi/node_modules/cassandra-driver/lib/streams.js:421:10)
at doWrite (_stream_writable.js:303:12)
at writeOrBuffer (_stream_writable.js:290:5)
at ResultEmitter.Writable.write (_stream_writable.js:219:11)
I've tried to adjust app.get like this to check to see if the array is empty:
app.get('/customer/:ent_cust_id', function (req, res, next) {
var query = 'Select * from entcustinfo where ent_cust_id = ' + req.params.ent_cust_id;
console.log('Select * from entcustinfo where ent_cust_id =' + req.params.ent_cust_id);
client.execute(query, function (err, result) {
if (err) return next (err);
var row = result.rows[0];
if (row.get('ent_cust_id') = '') {
res.send('ent_cust_id: ' + req.params.ent_cust_id + ' not found. Not all data is loaded.');
} else {
var row = result.rows[0];
//Response
res.json({ent_cust_id: req.params.ent_cust_id, accts: row.get('accts'), offers: row.get('offers')});
}
});
});
I'm thinking I need an if statement to check if no records were returned in results.rows and then do an res.send. I tried that but the same behavior still occures. How do I find out if no records were returned?
EDIT:
Made code changes in the first part...pasted in the wrong code...clarified question too.
It depends on the exact behavior of your client.execute(sql, callback(err, result)) function. You just have to test for what it returns on no results.
Ordinarily a callback from a database query will pass an empty array as the result if there are no results. So if you handle the case where result.length==0, you will no longer be trying to reference result[i].row.get on rows that no longer exist.
Although it is not the cause of this particular problem, you also want to escape your SQL queries. There is really no downside and it significantly increases your application security.
Let's attack the problem. First, your error:
TypeError: Cannot read property 'get' of undefined
This is node telling you that you wrote <object>.get, but when it tried to access the get property, it found that <object> was undefined.
Even more so, it's telling you where it happened:
/home/ec2-user/cassapi/app.js:16:14
Go to that file, and take a look at line 16. It's probably one of the 2 you posted:
app.get('/customer/:ent_cust_id', ...)
// or
row.get('offers')
So, you think app or row are objects with a get() method, but one of them must be undefined. This can happen for 2 reasons:
The app has a value of undefined-- was it assigned? Is it coming from another function? Did that function forget to return?
The row variable, assigned to result.rows[0], is undefined. Does result.rows have a [0] element? Could the array be empty?
Check the part where you create the app object, and the results you obtain .row[0] from. Use console.log to see their values. The error should be easy to spot.
//in your require, consider using below:
//var body-parser = require('body-parser'); // after installing with npm. I recommend globally installing
//app.use(body-parser()); //make sure you add this to initialize body parser after installing it. *NOTE: If using node with express 4.~ this is deprecated so ignore.
app.get('/customer/:ent_cust_id', function (req, res, next) {
//Your code: var query = 'Select * from entcustinfo where ent_cust_id = ?' [req.params.ent_cust_id];
/* Above, should probably include a plus sign between "?'" and "[req.params.....]; as below: */
var query = 'Select * from entcustinfo where ent_cust_id = ?' + [req.params.ent_cust_id];
//Another typo detailed below
//Your code: consolelog('Select * from entcustinfo where ent_cust_id = ?');
console.log('Select * from entcustinfo where ent_cust_id = ?');
/* Also, at this point you want to be logging your full query var, not your manually entered string value so type this as below: */
console.log(query); // shows your query, not your manually typed string.
//There really shouldn't ever be an issue with your manually typed query unless you need it surrounded in quotes.
//For greater clarification, whatever you're calling client below should be defined and expanded upon with an example.
/* In this code snippet, I typically always send the response first, if there is NOT an err liks so: if(!err){ //do the client's stuff first, else (if there's an error, does not need to be defined) { //do whatever else } Handling errors after it adds a small bit of speed to your process and reduces a step if you get a valid response and leaves error responding to secondary processing under the expectation you won't encounter an error */
client.execute(query, function (err, result) {
if(!err) { //do your client stuff first if no error then return next.
} else { console.log(err); return next} ; //No conditional needed for the error, because you've gotten here due to your code not working.
//if (err) return next (err);
var row = result.rows[0];
//Response
res.json({ent_cust_id: req.params.ent_cust_id, name: row.get('offers')}); /* Here you're responding with a JSON object as if you were querying a large JSON file. You may want to consider using res.send with and application/json response type. */
});
});
<div> For additional explanation on routing, you may want to look at express documentation here: express res.json</div>
<p> Also, make sure you're requiring body-parser in node so you can interpret incoming routes! </p>
<code> npm install -g body-parser </code>
Related
We are currently making a website for our roommate matching project. We are at the point where we are making the results page, which should display the 3 most compatible roommates based on some questions where the algorithm calculates their compatibility percentage.
We are now trying to pass the object called "fitness" that holds all of the results, which would be:
let fit = {
fitness: Math.round(sum * 100),
email: resident[i].email,
name: resident[i].firstName + " " + resident[i].lastName,
};
To our .ejs file called results.ejs. The fit object gets pushed into our global "fitness" variable.
This is our post request:
router.post("/results", function (request, response) {
let item = request.body;
let applicant_name = request.body.firstName;
client.connect(function (err) {
const db = client.db("myFirstDatabase");
assert.equal(null, err);
db.collection("residents").insertOne(item, function (err, result) {
assert.equal(null, err);
console.log("Item inserted");
});
});
client.connect(function (err) {
const db = client.db("myFirstDatabase");
assert.equal(null, err);
db.collection("residents")
.find({})
.toArray(function (err, resident) {
if (err) throw err;
/* weighting(request); */
compatability(request, resident);
});
});
client.close();
response.render("pages/results", {
applicant_name: applicant_name,
resident: fitness,
});
});
In our results.ejs file, we use Bootstrap cards in order to display the 3 most compatible roommates. This is the code we use in the results.ejs file:
<p class="card-text">
Compatibility %: <%= resident[0].fitness %><br />
Name: <%= resident[0].name %> <br />
Email: <%= resident[0].email %><br />
Location: <br />
</p>
Whenever we run the post request, we get an error saying "Cannot read properties of undefined (reading 'fitness')", but if we refresh again, the Node.js server crashes, but it displays the actual values we want to get. If we add a "?" after "resident[0]", it runs the page without any errors but does not display any information from the object.
We have tried numerous things but cannot find the right solution to solve this issue.
Thanks in advance.
EDIT
The whole code from the .ejs file and our serverside code, with photos of how it looks on the website: https://pastebin.com/zRxdk6aq
The error "Cannot read properties of undefined (reading 'fitness')" in this case means that resident[0] is undefined. This is probably due to the fact that residentis either undefined or is an empty array (length 0).
From the code you provided I can't see, where you actually push your object into the global fitness variable or where the variable is defined. Maybe that's were the problem is. To help you further with that, it would certainly help if you could post the code for that.
Edit:
Looking at the new code you provided in your pastebin, it looks like you're using asynchronus functions but are expecting a synchronus behaviour. Your current code looks essentially like this:
router.post("/results", function (request, response) {
client.connect(function (err) {
// Insert data into db
});
client.connect(function (err) {
// Fetch data from db
});
client.close();
response.render("pages/results", {
applicant_name: applicant_name,
resident: fitness,
});
});
The problem with that is, that your program does not wait for your DB-operations to finish before rendering your page. This is because of how callback functions work.
I presume you are using the mongoDB driver for nodejs. Besides classic callback options, it also allows for the use of async/await:
router.post("/results", async (request, response) {
//
await client.connect();
const db = client.db('myFirstDatabase');
await db.collection("residents").insertOne(request.body);
let residents = await db.collection("residents").find({}).toArray();
let fitness = compatability(request, resident);
client.close();
response.render("pages/results", {
applicant_name: request.body.firstName,
resident: fitness,
});
});
function compatability(request, resident) {
let fitness = [];
// Do your calculations here
return fitness;
}
This way your request handler waits until you inserted your new item into the db and fetched the existing ones. Only after that, it renders your page and thereby ensures, that the fitness variable is already filled with data.
Note that in this example I also suggest to change your compatability function so that it returns your `fitness´ variable instead of making it global.
If you aren't familiar with async/await I recommend that you also try to learn about Promises.
In general how does javascript interpret a Database {} object? I am writing some back end scripts to handle a registration form verification. In particular I need to ensure that the username and email used to register is not currently in use. To do this I use the sqlite3 package and use a few db.get calls to determine if there are existing entries in my database for the username and email used on the registration form. I want to use the return of db.get to check if it is empty or not and use this conditional to perform the necessary task. However the db.get returns a Database {} object which I am unfamiliar of how to work with.
Hopefully the following pseudo describes the issue better. Here uname returns Database {} and so never fails the if statement.
function existance(username, email) {
let uname = db.get(sql, username, callback(err, throw));
if (uname) {
let errors = {username: 'Username already in use.'};
return errors;
}
};
EDIT
I have since used Gajiu's recommendation but still having issues. So I have two files:
registrant_existence.js
// necessary requirements and initialisation
function registrant_existence(username) {
let uname;
let sql = 'SELECT username FROM table WHERE username=?';
db.get(sql, username, function(err, row) {
if (err) {
throw err;
} else {
uname = row;
console.log(uname);
}
});
console.log(uname);
if (uname !== undefined) {
return {username: 'Username already in use.'};
} else {
return 'DNE';
}
};
module.exports = registrant_existence;
register.js
let registrant_existence = require("path to registrant_existence.js");
// necessary requirements and initialisation
router.post('/', function(req, res) {
let existence = registrant_existence(req.body.username, req.body.email);
if (existence != 'DNE') {
// render registration page notifying the user
// that the username is already in use
} else {
// register the new user details
}
});
The uname variable is undefined always. I placed the console.log(uname) in two spots in registrant_existence.js as is seen above to see what is happening. Two strange things occur.
The first is that the console.log(uname) outside the db.get() displays undefined in the console and the console.log(uname) inside the db.get() displays the expected string (a username I know is in my database).
The second is that the console.log(uname) outside the db.get() is displayed before the console.log(uname) _inside the db.get() in my console.
I have no idea why these things are happening. Does anyone have any suggestions?
You should try something like that:
db.get(sql, username, (err, data) => {
// process the data here
if (err) {
return console.error(err.message);
}
return data
? console.log(data.id, data.userName)
: console.log('No username found');
});
I guess you are looking for a wrapper around your Database object, something like an Object Relational Mapper (ORM), this one is used regularly https://sequelize.org/master/manual/getting-started.html
On the other hand for your specific use case you might want to get a look at this https://www.sqlite.org/lang_createtable.html#unique_constraints: unicity is usually via constraints in the data store.
I have an express.js app that needs to run a script on the server in order to derive some values using functions later. Here's the gist of it:
shell.exec(commandString);
readFolder();
renderPage();
Essentially, I need to run a script on the server, then run the second function, then run the third function. These need to happen subsequently, but it seems that javascript moves on ahead with the the second and third function no matter what I do. I've tried promises, async, callbacks. All of which I only partially understand and seem to get zero progress.
I will admit that I am a javascript novice. I am working on a project with others and this task fell to me. I doubt this is the best way to accomplish our ultimate goals, but I am left with little choice. please help.
I'll put the entire post here for reference:
//Run script when post is rec'd from root and send to results page
app.post("/", (req, res) => {
var commandString;
//take values and create complete command for Astrum script
commandString = 'bash /home/astrum/Main/Astrum.sh -s ' + req.body.speed + ' -h ' + req.body.host + ' -u ' + req.body.username + ' -p ' + req.body.password;
//execute command in shell
shell.exec(commandString);
readFolder();
renderPage();
//Iterate thru filenames to create arrays for links and link labels
function readFolder() {
fs.readdir('./reports/html/', (err, files) => {
//variable & method for links to html records pages
ipAddressesLink = files; //this is initialized earlier, globally
//variable and method to remove file extension for link labels in pug
ipAddresses = files.map(removeExtension); //this is initialized earlier, globally
});
}
//function to remove last five characters of each element
function removeExtension(value) {
return value.substring(0, value.length - 5);
};
//function to render the page
function renderPage() {
res.render("results", {ipAddressesLink, ipAddresses, title: 'Results'});
}
res.end();
});
You could write it this way:
shell.exec(commandString, (error, stdout, stderr) => {
// Calling the 1st function after shell command is executed
readFolder();
});
function readFolder() {
fs.readdir('./reports/html/', (err, files) => {
// Some stuff
...
// Calls the 2nd function after fs is done reading files
renderPage();
});
}
function renderPage() {
const options = { ... }; // IP addresses etc.
res.render(
"results",
options,
// Calls the final function after render is finished
sendResponse
);
}
function sendResponse(err, html) {
// Sends the response. It’s possible that res.send() is the better solution here
res.end();
}
It’s just the general structure of the callback chain, definitely not the cleanest one. If you want better code structure and readability try switching to async / await syntax.
Is shell here the child_process module? If it is then you can pass an optional callback argument and call your functions from there.
shell.exec(commandString, (error, stdout, stderr) => {
const files = readFolder();
renderPage(files);
});
function readFolder() {
...
return fs.readdirSync(files);
}
function renderPage(files) {
...
}
I've had this problem before twice. The first time, it was because the returned object was actually an unfulfilled promise, and I was able to get around it by throwing all my code inside of the block so that it would execute in there. Not exactly an ideal solution but it worked and I was in a hurry.
The second time I was using pg-promise instead of just pg, and when this issue popped up I thought "it must be that damn promise again", so instead of tearing my hair out I just uninstalled pg-promise and went with the regular postgres package for nodejs instead. Well, the problem is still here and I'm tearing my hair out.
I'm making an API. I have a controller with functions such as getPayment and postPayment and so on. At some point in these functions, I need to get information from or into the database. In another file, which I called postgres.js, I have a connection to the database and then functions which I can call to insert data, select, etc.
Here is postgres.js as it is right now (this works but only for printing to console):
module.exports = {
select: select
};
const { Client } = require('pg');
const client = new Client({
user: 'myUser',
host: 'localhost',
database: 'myDB',
password: 'myPassword',
port: 5432,
});
client.connect();
function select(){
client.query('SELECT * FROM payments', (err, res) => {
console.log(err ? err.stack : res.rows[0].id);
client.end();
});
}
As you can see right now all it does is get the payments from the table and print a value (in this case, the first row's id) to console.
Here is the code that calls this function, from the controller (payments.js):
var pg = require('../../config/postgres.js')
...
function getPaymentInfo(params){
// get info from the DB
// disregard the fact that I'm not sending any params right now, this is for testing
var result = pg.select();
console.log(result);
console.log(typeof result);
}
Calling pg.select() does in fact activate the select function on postgres.js (and the console log correctly prints the data in res.rows[0].id) however when I try putting a return res.rows[0].id there in order to actually return the information that was retrieved from the database, what comes back into the var result is "undefined" according to the console. Here are a few examples of things I've tried to do to get the data out:
function select(){
var i = '';
client.query('SELECT * FROM payments', (err, res) => {
//console.log(err ? err.stack : res.rows[0].id);
i = err? err.stack : res.rows[0].id;
client.end();
});
return i;
}
I tried this with and without commenting the console.log line, either way it doesn't work.
function select(){
client.query('SELECT * FROM payments', (err, res) => {
//console.log(err ? err.stack : res.rows[0].id);
return res.rows[0].id;
//client.end();
});
}
I figure this would be wrong since I'm returning without checking for an error, but I tried just to see what would happen... undefined again.
function select(){
client.query('SELECT * FROM payments', (err, res) => {
//console.log(err ? err.stack : res.rows[0].id);
return err ? err.stack : res.rows[0].id;
//client.end();
});
}
This time checking for err, still returns undefined.
function select(){
return client.query('SELECT * FROM payments', (err, res) => {
//console.log(err ? err.stack : res.rows[0].id); // Hello World!
client.end();
return err ? err.stack : res.rows[0].id;
});
}
Returning the return from client.query(etc etc);.. same thing as before. Also tried without the explicit return, without checking for error, all the same.
Here's the last test I tried:
function select(){
var i = 'original i';
client.query('SELECT * FROM payments', (err, res) => {
console.log(err ? err.stack : res.rows[0].id); // Hello World!
if (err){
i = "i has changed!";
} else {
i = "i has not changed!";
}
client.end();
});
return i;
}
The console shows this:
original i
string
2
That last "2" being res.rows[0].id.
I really believe this must have something to do with the blasted "promises" and asyncronous stuff. But my previous "solution" won't fit here. I can't just do everything inside of that block where I have access to res. I have to be able to return some data back to getPaymentInfo().
It seems that client.query(...) is waiting for every line in getPaymentInfo() to be ran before actually doing anything. I can see that because in the console, the results of console.log(result) and console.log(typeof result) appear before the line that shows information from the table (from console.log(err ? err.stack : res.rows[0].id) ). That is absolutely infuriating.
I called the pg.select() function. That function calls client.query(). client.query should do its thing, return to select(), which would then return to getPaymentInfo() and then keep going and do what the next lines say. That's normal behaviour for any program. Clearly that's not happening here.
I saw some examples out there that used await, but when I tried to add that copying the examples, it gave me a syntax error as if it didn't recognize what await is supposed to be. There was an example with yield as well, same error. It doesn't know what those commands mean. I'm using the latest version of nodejs (v8.10.0).
I also tried using then to get it to wait:
function generatePaymentInfo(params){
...
pg.select().then(function(v) {
console.log(v);
});
...
}
It gives me this error:
TypeError: Cannot read property 'then' of undefined
What's going on here? How do I get it to do things in the right order? All I want is to get some information from a table. Every example for the pg package (and pg-promise as well) I see out there just has a console.log() representing "success". In reality what anyone would want is to have actual access to the data.
I would like to 'functionalize' my queries by putting them into functions which have apt names for the task.
I want to avoid putting everything in the req, res functions (my controllers), and instead put them in 'models' of sorts, that is, another JavaScript file that will be imported and used to run the functions that execute queries and return the results on behalf of the controller.
Assuming that I have the following setup for the queries:
UserController.js
exports.userAccount = function(req, res, next) {
var queryText = "\
SELECT *\
FROM users\
WHERE id = $1\
";
var queryValues = [168];
pg.connect(secrets.DATABASE_URL, function(err, client, done) {
client.query(queryText, queryValues, function(err, result) {
res.render('pathToSome/page', {
queryResult: result.rows
});
});
});
}
Here, while I'm in the query, I essentially redirect and render a page with the data. That works fine. But I want to take out all that pg.connect and client.query code and move it to a separate file to be imported as a model. I've come up with the following:
UserModel.js
exports.findUser = function(id) {
// The user to be returned from the query
// Local scope to 'findUser' function?
var user = {};
var queryText = "\
SELECT *\
FROM users\
WHERE id = $1\
";
var queryValues = [id];
pg.connect(secrets.DATABASE_URL, function(err, client, done) {
client.query(queryText, queryValues, function(err, result) {
// There is only ever 1 row returned, so get the first one in the array
// Apparently this is local scope to 'client.query'?
// I want this to overwrite the user variable declared at the top of the function
user = result.rows;
// Console output correct; I have my one user
console.log("User data: " + JSON.stringify(user));
});
});
// I expect this to be correct. User is empty, because it was not really
// assigned in the user = result.rows call above.
console.log("User outside of 'pg.connect': " + JSON.stringify(user));
// I would like to return the user here, but it's empty!
return user;
};
and I'm calling my model function as so:
var user = UserModel.findUser(req.user.id);
The query executes perfectly fine in this fashion - except that the user object is not being assigned correctly (I'm assuming a scope issue), and I can't figure it out.
The goal is to be able to call a function (like the one above) from the controller, have the model execute the query and return the result to the controller.
Am I missing something blatantly obvious here?
pgconnect is an asynchronous call. Instead of waiting for data to return from the database before proceeding with the next line, it goes ahead with the rest of the program before Postgres answers. So in the code above, findUser returns a variable that has not yet been populated.
In order to make it work correctly, you have to add a callback to the findUser function. (I told you wrong in a previous edit: The done parameter in pg.connect is called in order to release the connection back to the connection pool.) The final result should look something like this:
exports.findUser = function(id, callback) {
var user = {};
var queryText = "SELECT FROM users WHERE id = $1";
var queryValues = [id];
pg.connect(secrets.DATABASE_URL, function(err, client, done) {
client.query(queryText, queryValues, function(err, result) {
user = result.rows;
done(); // Releases the connection back to the connection pool
callback(err, user);
});
});
return user;
};
And you'd use it, not like this:
var user = myModule.findUser(id);
But like this:
myModule.findUser(id, function(err, user){
// do something with the user.
});
If you have several steps to perform, each of them dependent on data from a previous asynchronous call, you'll wind up with confusing, Inception-style nested callbacks. Several asynchronous libraries exist to help you with making such code more readable, but the most popular is npm's async module.