PostgreSQL REST API Node.js CRUD - String query parameter giving error - node.js

I am setting up my first REST API to query a Postgres database I set up. I have two CRUD methods that currently work that query for all rows in a table and for rows where ID = something, respectively.
The problem I'm having occurs when trying to query when the request parameter is a String. Here is the error I'm getting:
error: invalid input syntax for type integer: "NaN"
Here is how I've set up my GET route and endpoint URL:
const getShowByTitle = (request, response) => {
const title = request.params.title
pool.query('SELECT * FROM show WHERE title = $1', [title], (error, results) => {
if (error) {
throw error
}
response.status(200).json(results.rows)
})
}
app.get('/show/:title', getShowByTitle)
Expected result is that sending a GET request using a show title as a parameter (String) returns a JSON response of just that show.
Any help or direction to some useful resources would be greatly appreciated. Thank you.

There are some issues here, first in SQL the name of the tables should be in plural "shows", second you are making the select without quotes, you need something like:
"SELECT * FROM show WHERE title = '$1'"
Third, since the user can use uppercase and down cases you need a more robust way to search for text using LIKE, ILIKE and ~, ~* operators.
https://www.2ndquadrant.com/en/blog/text-search-strategies-in-postgresql/
Fourth and more important, you are not filtering the string and you are at risk of suffering an SQL injection because "UPDATE admins SET password='newsom22th88';" is going to be executed in your database.

After some debugging my original code wasn't working because I had multiple verb-route matches. I solved the issue by creating a new unique verb-route match. Below is my complete code for querying using a String. Aarkerio's other points still hold; I need to alter my code to avoid SQL injection as well as create a more robust search.
const getShowByTitle = (request, response) => {
const title = request.params.title
pool.query('SELECT * FROM show WHERE title = $1', [title], (error, results) => {
if (error) {
throw error
}
response.status(200).json(results.rows)
})
}

Related

Postgres Node search query using LIKE, how to set %

I have a weird problem I encountered using Postgresql and Node. I would like to use LIKE in my query together with % at the beginning and end of searched term. I have no issue using it in the plain SQL:
THIS WORKS:
SELECT * FROM vehicle WHERE module_imei LIKE '%searchterm%' OR custom_id LIKE '%searchterm%'
However, using it in Node is a bit of challenge. I haven't been successful in resolving it yet:
THIS DOES NOT WORK:
getVehiclesSearch: async function({ search }) {
let response;
try {
response = await pool.query(`SELECT * FROM vehicle WHERE module_imei LIKE %$1% OR custom_id LIKE %$1%`, [search]);
if(response) return response.rows;
} catch(error) {
// handle error
console.error(error);
// do not throw anything
}
},
Doing above will produce: syntax error at or near "%"
SELECT * FROM vehicle WHERE module_imei LIKE '%${$1}%' OR custom_id LIKE '%${$1}%
Doing above will produce: $1 is not defined
SELECT * FROM vehicle WHERE module_imei LIKE '%$1%' OR custom_id LIKE '%$1%'
Doing above will produce: bind message supplies 1 parameters, but prepared statement "" requires 0
I kind of struggle factoring the % in so it won't crash the query. Simply run out of ideas after trying above and variables of those. Thanks for your kind help.
This has been already answered over here:
Go postgresql LIKE query
In this particular case:
response = await pool.query(`SELECT * FROM vehicle WHERE module_imei LIKE '%'||$1||'%' OR custom_id LIKE '%'||$1||'%'`, [search]);
This would work.
You are missing single quotes, also I don't recognize a db adapter you use, but you can use template literals (watch out for sql injection!!!)
response = await pool.query(`SELECT * FROM vehicle WHERE module_imei LIKE '%${search}%' OR custom_id LIKE '%${search}%'`);

Updating specific MongoDB document based on ID passed in from pug-based express route

I'm attempting to update a single row of a table within a pug page. The rows of this table are populated from MongoDB. The cells of these table rows are populated using document data e.g. doc.name, while the actual table row contains the document's ID e.g. doc._id.
tr(id = doc._id)
form.hidden(method = "patch", action = "../update" + doc._id)
td button.btn(type = "submit") Update
td
input(name = "name", value = "doc.name")
td
input(name = "age", value = "doc.age")
The route for this operation is shown below:
router.patch("../update/:id", Controller.update)
The controller's update function is:
exports.update = (req, res, next) => {
const id = req.params.id;
const operations = {};
for(const task of req.body){
operations[task.propName] = task.value;
}
Feature.update({_id: id}, {$set: operations})
.exec()
.then(
res.status(200)
)
.catch(
res.status(500)
)
}
I'm able to enter and submit the change, then pass the URL back through an Express route ../update/:id so that the request equals GET ../update/testID123?name=testName&age=42 404. I understand that this means the ID can't be found, but I'm perplexed as to why not? It was my understanding that the last section of the URL was represented as req.params and anything after ? was the req.body?
However, when I conduct the identical request using a defined PATCH request via Postman, I receive a different error mentioning that req.body is not iterable, but I don't understand how to force differentiation between the auto-selected GET request and the desired PATCH request. It's worth noting that I've already followed the path to the "not iterable" error as outlaid in this post, so I don't think this is the real problem.
It's the end of the day and my brain has turned to mush, so apologies for missing out any key details, and thanks for reading.
Found the answer thanks to advice given in this post. I was accessing aspects of an object that didn't exist, in a manner that wasn't suitable for iteration as outlaid in the linked post. I was wrong in thinking that the req.body not iterable error was a red herring, so I re-implemented the task of Object.keys(req.body) loop and instead of appending [task.propName] = task.value to the updateOperations array, I had to implement [task] = req.body[task].

using nodejs with pattern matching in CQL

const query= 'SELECT * FROM TEST WHERE "partitionId" = \'sr\' AND "name" LIKE \'%?%\'';
db.execute(query, ['B']).then(function(res) {
console.log(res);
}).catch(function(error) {
console.log(error);
});
I was not able to select data based on the pattern specified in the array.What is the exact way using CQL pattern matching with nodejs.I am getting "Invalid amount of bind variables" error.
NOTE: db has all the connection parameters
I think that you need to use following instead
const query= 'SELECT * FROM TEST WHERE "partitionId" = \'sr\' AND "name" LIKE ?';
db.execute(query, ['%B%']).then(function(res) {
...
P.S. Do you have corresponding indices built that support the LIKE expression? Cassandra doesn't work the same way as "standard" SQL databases.

Node.js Dynamodb Issue Using getItem

I have written the following code to return a row from a Dynamodb table based on a key called id.
var db = new AWS.DynamoDB();
var params = {
AttributesToGet: [
"dealername"
],
TableName : "syv_dealer",
Key : {
"id" : {
"S" : "1"
}
}
}
db.query(params, function(err, data) {
if (err) {
console.log(err); // an error occurred
} else {
console.log(data); // successful response
}
});
My code to write the data to the table worked fine, but the above code keeps generating the following error: Unexpected key 'Key' found in params
The table exists and there is an id attribute with a value of "1" in the table.
I have looked at all the examples I could find and have changed the params statement a hundred times, but nothing has worked. I am sure it is something simple, but any help would be appreciated.
This is failing because Key is an invalid parameter for submitting a request to that API. Look at the DynamoDB Query syntax to determine what attributes you can set.
The proper way to perform this query would be with a KeyConditionExpression which would look something like:
var params = {
TableName : "syv_dealer",
KeyConditionExpression: "id = :v1",
ExpressionAttributeValues: {
":v1": {"S": "1"}
},
ProjectionExpression: "dealername"
}
Using ProjectionExpression instead of AttributesToGet is also the modern way of specifying attributes.
Thank you, I had changed things so much I hadn't realized I had changed it from a getItem to Query.
The crux of my problem all along was that the function call is asynchronous, so I wasn't being patient and letting the callback execute.
I am new to Node.js, so I am trying to figure out how to check the credentials on a web service call and not have it continue until I have authenticated the requestor. Is there a way on the getItem call to have it be synchronous? I realize I could embed the logic that follows within the getItem callback, but I was really trying to use the same security routine for every endpoint.
Thoughts?

How to return multiple Mongoose collections in one get request?

I am trying to generate a response that returns the same collection sorted by 3 different columns. Here's the code I currently have:
var findRoute = router.route("/find")
findRoute.get(function(req, res) {
Box.find(function(err, boxes) {
res.json(boxes)
}).sort("-itemCount");
});
As you can see, we're making a single get request, querying for the Boxes, and then sorting them by itemCount at the end. This does not work for me because the request only returns a single JSON collection that is sorted by itemCount.
What can I do if I want to return two more collections sorted by, say, name and size properties -- all in the same request?
Crete an object to encapsulate the information and chain your find queries, like:
var findRoute = router.route("/find");
var json = {};
findRoute.get(function(req, res) {
Box.find(function(err, boxes) {
json.boxes = boxes;
Collection2.find(function (error, coll2) {
json.coll2 = coll2;
Collection3.find(function (error, coll3) {
json.coll3 = coll3;
res.json(json);
}).sort("-size");
}).sort("-name");
}).sort("-itemCount");
});
Just make sure to do the appropriate error checking.
This is kind of uggly and makes your code kind of difficult to read. Try to adapt this logic using modules like async or even promises (Q and bluebird are good examples).
If I understand well, you want something like that : return Several collections with mongodb
Tell me if that helps.
Bye.
Have you tried ?
Box.find().sort("-itemCount").exec(function(err, boxes) {
res.json(boxes)
});
Also for sorting your results based on 2 or more fields you can use :
.sort({name: 1, size: -1})
Let me know if that helps.

Resources