node-postgres why is req.query.record empty? - node.js

When I start my nodejs app (with dust) on localhost:3000 the following code is used to grab all rows from my products tables (postgres db) and display them on my index page. It seemed to work fine last week.
app.get('/', async (req, res) => {
var parms = req.query.record;
const results = await pool.query('SELECT * FROM products WHERE id = $1',[parms], function (err, result) {
if (err) {
return console.error('error running query', err);
}
res.render('index', { products: result.rows });
});
});
For some reason now "req.query.record" is empty "[ ]" so no results are displayed on my index page.
If I navigate to localhost:3000/?record=3 it works fine and I can see the one record on my index page.
Also, if I edit the "results" in the original code and change [parms] to [3] then it works fine as well and displays that one record on my index page.
what would cause var parms = req.query.record; to return an empty object? Is that the expected behavior?

Okay, I think I have it. Bergi (it is the request) is correct and it was the expected behavior. I started the code from a tutorial posted before July 2017. the original pg.connect was hard deprecated. pg.connect not a function?
As a result I started hacking together something with the new pg.Pool(...).connect(...). The method described in my original question must have gotten mushed up with something else. As far as I know there is no need to process any query string from the index page when I am trying to return all rows from a table.
There is nothing after http://localhost:3000 which is why the result was an empty object. that is the expected behavior. http://localhost:3000/?record=3 did return the one row because req.query.record picked out [3] from the query string which is the expected behavior. The method in the original question would be used for returning one row from the table when the id is passed in the query string.
for my purposes, returning all rows, I replaced my app.get with...
app.get('/', async (req, res) => {
await pool.query('SELECT * FROM library', function (err, result) {
if (err) {
return console.error('error running query', err);
}
res.render('index', { recipes: result.rows });
});
});
If I wanted to use both methods I guess I would first run a check to see if there is a query string then proceed with the original app.get if true. else run the second app.get method to get all rows.
I just started with NodeJS and Postgres but am not sure why I didn't notice that from the get-go. Not sure if this will be a useful question/answer for anyone but I'll leave it up.

Related

res.render() calls promise twice expressjs

Hello I am still a beginner in Nodejs and MongoDB. When I am running res.render() function as shown below I get 2 console logs, first with the correct result from mongodb find query and second with null. If I remove res.render() It works properly with only one console.log() output and not the second null.
router.get('/:areaslug', (req, res) => {
// Query results
let areavar = {}
return client.db("AwesomeApartments")
.collection("areas")
.findOne({slug: req.params.areaslug
})
.then((datadb) => {
// first time shows correct results next it shows null
console.log(" bug-testing : "+JSON.stringify(datadb));
//storing result of first query to my object
areavar = datadb;
return client.db("AwesomeApartments")
.collection("apartments")
.find({area:datadb._id})
.toArray()
})
.then((apartmentdb) => {
// Storing results of second query
areavar.apartments = apartmentdb;
//removing this solves the issue
return res.render('area',areavar);
}).catch(err =>
{
console.log(err);
return;
})
});
To those who find their way here, browser was generating two get requests. First one for query and second one for favicon.ico. Handling favicon.ico request solved this issue.

NodeJS Express: how to get object item

I try to create a simple login form and fail to validate the password from the MongoDB.
First I create the .post route for the form validation and then I get the MongoDB data which I want to compare with the form.
Here is my code:
app.post('/users', (req, res) => {
const reqUser = req.body.params.name
const reqPW = req.body.params.password
// connect to mongoDB
const collection = client.db().collection("users")
collection.find({name: reqUser}).toArray(function (err, results) {
if (err) {
console.log(err)
res.send([])
return
}
else {
console.log('RESULT', results) // returns the object
console.log('RES PW', results.password) // returns undefined
// this does not work
Object.keys(results).forEach(function(key) {
console.log('key is: ', key); // returns 0
});
// validate user+pw
if (!reqUser || !reqPW/*|| reqPW !== password*/) {
return res.status(401).end()
}
// send result to frontend
res.send(results)
res.end
}
})
})
So, I get my object returned in results but I cannot get the data from the object.
I also tried to convert it to an array with Array.from() but that didn't work either.
Please note that I did not yet implement hashing and salting the passwords yet, as I thought I want a working validation first. Do I need to implement those first?
I just checked the doc:
The toArray() method returns an array that contains all the documents from a cursor. The method iterates completely the cursor, loading all the documents into RAM and exhausting the cursor.
So toArray() will return a array, not object, therefore your results will be an array containing all the items(object) you get from the db. If you console.log(results), it should print an array rather than object.
Assuming there won't be two users have the same name, the results you get will be just an array containing one object, so you can just do:
results[0].password // get the first object's password field
Not sure if this slove your question, but based on your code thats the problem i found in it.

Not able to return posts by user id

When trying to fetch all the posts by a user id, cosmos DB only return an empty array, but when using mongo DB through atlas, it returns all the posts by that user. What am i doing wrong.
exports.postsByUser = (req, res) => {
Post.find({ postedBy: req.profile._id })
.populate("postedBy", "_id name")
.select("_id title body created likes")
.sort("_created")
.exec((err, posts) => {
if (err) {
return res.status(400).json({
error: err
});
}
res.json(posts);
});
`enter code here`};
I receive a http status of 200, but with just an empty array. and when i try fetching all the posts by all users it returns.
I know this might not be "the answer" but it is a suggestion which will bring others to the correct answer in their case.
For those who run into bugs like these, the easiest way to find out what is happening and which step is making the unexpected return is to comment out all the pipeline steps, in this case, populate, select and sort. Then debug from there - if it returns anything, if there is no result you can start from your match case (find), if it does return you can move to next pipeline step and so on.
Taking some time debugging yourself will make you understand your code better, and you will find the answer yourself faster than waiting for someone on stackoverflow to give u suggestions.

Error when using moment.max with the results of a mongoDB query

I am working on a nodeJS application that inserts documents into a mongoDB collection. The document has a createdAt field that records the time of creation. I also have a function that logs the most recent match of a query to the console.
Code:
function getResult(player){
let timeList = [];
MongoClient.connect(url, (err, db) => {
if(err){
console.log(err);
}
else{
let count = db.collection('PokeBook').count({ 'player1': player }); //count function returns a promise
count.then((val) => {
db.collection('PokeBook').find({ 'player1': player }).forEach((doc) => {
timeList.push(doc.createdAt);
console.log(doc.createdAt);
if(val===timeList.length){
myEmitter.emit('full', timeList);
}
});
});
}
});
}
//code for the emitter:
myEmitter.on('full', (arr) => {
console.log('full emitted');
console.log(moment.max(arr));
});
the code returns an error saying moments[i].isValid is not a function. Commenting the moment.max line of code results in successfully logging "full emitted" to the console.
Any advice on why this happens and how to fix this will be much appreciated. :)
moment.max() expects an array of Moment objects, but doc.createdAt is (probably) a regular Date object. You can try to replace:
timeList.push(doc.createdAt);
with:
timeList.push(moment(doc.createdAt));
so arr would be an array of Moment objects.
Alternatively, you can implement max yourself w/o using moment, assuming doc.createdAt is either Date or Number:
console.log(arr.sort()[arr.length-1]);

How can I execute queries one after the other and extract value from 1st query and use it in the 2nd using expressJS?

router.post("/application_action", function(req,res){
var Employee = req.body.Employee;
var conn = new jsforce.Connection({
oauth2 : salesforce_credential.oauth2
});
var username = salesforce_credential.username;
var password = salesforce_credential.password;
conn.login(username, password, function(err, userInfo, next) {
if (err) { return console.error(err); res.json(false);}
// I want this conn.query to execute first and then conn.sobject
conn.query("SELECT id FROM SFDC_Employee__c WHERE Auth0_Id__c = '" + req.user.id + "'" , function(err, result) {
if (err) { return console.error(err); }
Employee["Id"] = result.records[0].Id;
});
//I want this to execute after the execution of above query i.e. conn.query
conn.sobject("SFDC_Emp__c").update(Employee, function(err, ret) {
if (err || !ret.success) { return console.error(err, ret);}
console.log('Updated Successfully : ' + ret.id);
});
});
I have provided my code above. I need to modify Employee in the conn.query and use it in conn.sobject. I need to make sure that my first query executes before 2nd because I am getting value from 1st and using in the 2nd. Please do let me know if you know how to accomplish this.
New Answer Based on Edit to Question
To execute one query based on the results of the other, you put the second query inside the completion callback of the first like this:
router.post("/application_action", function (req, res) {
var Employee = req.body.Employee;
var conn = new jsforce.Connection({
oauth2: salesforce_credential.oauth2
});
var username = salesforce_credential.username;
var password = salesforce_credential.password;
conn.login(username, password, function (err, userInfo, next) {
if (err) {
return console.error(err);
res.json(false);
}
// I want this conn.query to execute first and then conn.sobject
conn.query("SELECT id FROM SFDC_Employee__c WHERE Auth0_Id__c = '" + req.user.id + "'", function (err, result) {
if (err) {
return console.error(err);
}
Employee["Id"] = result.records[0].Id;
//I want this to execute after the execution of above query i.e. conn.query
conn.sobject("SFDC_Emp__c").update(Employee, function (err, ret) {
if (err || !ret.success) {
return console.error(err, ret);
}
console.log('Updated Successfully : ' + ret.id);
});
});
});
});
The only place that the first query results are valid is inside that callback because otherwise, you have no way of knowing when those asynchronous results are actually available and valid.
Please note that your error handling is unfinished since you don't finish the response in any of the error conditions and even in the success case, you have not yet actually sent a response to finish the request.
Original Answer
First off, your code shows a route handler, not middleware. So, if you really intend to ask about middleware, you will have to show your actual middleware. Middleware that does not end the request needs to declare next as an argument and then call it when it is done with it's processing. That's how processing continues after the middleware.
Secondly, your console.log() statements are all going to show undefined because they execute BEFORE the conn.query() callback that contains the code that sets those variables.
conn.query() is an asynchronous operation. It calls its callback sometime IN THE FUTURE. Meanwhile, your console.log() statements execute immediately.
You can see the results of the console.log() by putting the statements inside the conn.query() callback, but that is probably only part of your problem. If you explain what you're really trying to accomplish, then we could probably help with a complete solution. Right now, you're just asking questions about flawed code, but not explaining the higher level problem you're trying to solve so you're making it hard for us to give you the best answer to your actual problem.
FYI:
app.locals - properties scoped to your app, available to all request handlers.
res.locals - properties scoped to a specific request, available only to middleware or request handlers involved in processing this specific request/response.
req.locals - I can't find any documentation on this in Express or HTTP module. There is discussion of this as basically serving the same purpose as res.locals, though it is not documented.
Other relevants answers:
req.locals vs. res.locals vs. res.data vs. req.data vs. app.locals in Express middleware
Express.js: app.locals vs req.locals vs req.session
You miss the basics of the asynchronous flow in javascript. All the callbacks are set to the end of event loop, so the callback of the conn.query will be executed after console.logs from the outside. Here is a good article where the the basic concepts of asynchronous programming in JavaScript are explained.

Resources