Why is POST request with pool.query only works intermittently when using :id in the middle of URL? - sql

I wasn't quite sure how to phrase this question so feel free to make corrections to improve it as desired.
My goal is to make an HTTP POST that will create comments for a post and add the comment to the database comments table. I believe this necessitates doing an INSERT as well as a JOIN to add the specific POST id to the comment.
This is my first time including two requests in one query so I am unsure if this is correct. I had read about using a UNION but haven't been able to figure out the correct syntax as none of the examples included quotes '' around their requests.
My post route:
router.post(`/posts/:id/comments`, (request, response, next) => {
const { id } = request.params; // tried with and without brackets {}
const { comment_body } = request.body;
// Testing for correct params
console.log(id);
console.log(comment_body);
pool.query(
'INSERT INTO comments(comment_body) VALUES($1)',
[post_id, comment_body],
'SELECT * FROM comments JOIN posts ON posts.post_id = commments.post_id',
(err, res) => {
if (err) return next(err);
}
);
});
What is strange is that this worked twice then stopped working. There are two entries in the comments table but any further posts don't do anything. This only worked from the comments form and not yet in Postman
This worked in two separate tests. When using brackets around the id, the post was created in the table but no post_id was joined on this table:
const { id } = request.params;
If I didn't use the brackets, the post_id was created in the data table:
const id = request.params;
Here are my tables:
CREATE TABLE posts(
post_id SERIAL,
user_id INT,
post_body CHARACTER varying(20000)
);
CREATE TABLE comments(
id SERIAL,
post_id INT,
user_id INT,
comment_body CHARACTER varying(20000)
);
Originally I had the post_id for comments set as serial but figured if that is supposed to be joined from the posts.post_id, it would probably need to be INT.
Thanks much for any direction.

I managed to solve this with the following:
router.post(`/posts/:id/comments`, async (request, response, next) => {
try {
const { id } = request.params;
const { comment_body } = request.body;
await pool.query
('INSERT INTO comments(post_id, comment_body) VALUES($1, $2)',
[id, comment_body]);
} catch(error) {
console.log(error.message)
}
});
Rather than using the JOIN, I just included the posts ID parameter in the original INSERT and imported it that way. I had initially thought I had to do it as a join but couldn't get a second SQL request to work. Thanks to snakecharmerb for the idea.
I also added async/await.

Related

node-postgres not parsing queries correctly

I am trying to count the number of documents in a table that satisfy a condition.
My code in node:-
const [washingCount, washedCount, dirtyCount] = await Promise.all([
pool.query("SELECT COUNT(*) FROM clothes WHERE status = 'washing'"),
pool.query("SELECT COUNT(*) FROM clothes WHERE status = 'washed'"),
pool.query("SELECT COUNT(*) FROM clothes WHERE status = 'dirty'")
])
But I am getting the error saying:
error: column "count" does not exist
And when I copy the same query over to PostgreSQL CLI, those output the desired results.
For full code refer:- https://github.com/js313/clothio/blob/master/index.js
Error stack trace:-
What am I missing here?
Thank you.
Why don't use group by?
select status, count(*) from clothes group by status
Edit
tested with a simple script like this and worked
require("dotenv").config({ path: "./.env" });
const Pool = require("pg").Pool;
const pool = new Pool({
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB_NAME,
});
async function main() {
const result1 = await pool.query("SELECT now()");
console.log(result1);
const result = await pool.query(
"SELECT status, COUNT(*) FROM clothes group by status"
);
console.log(result.rows);
}
main()
.then()
.catch((e) => console.error(e));
Edit 2
Found the issue in your repo code.
Route registration order matters, so you have this route.
app.get("/clothes/:cloth_id", async (req, res) => {
before the count one, so express is getting into this route and never reaching the count one.
To solve the issue move the /clothes/count route before the clothes/clothe_id one and that should solve the issue

Supabase, filter by column value of foreign key row

I am trying to figure out how to implement a query in supabase:
Schema
CREATE TABLE cars
(
id SERIAL PRIMARY KEY,
brand TEXT
);
CREATE TABLE stores
(
id SERIAL PRIMARY KEY,
car INT REFERENCES car(id),
name TEXT
);
I want to get all stores which carry the car of brand "x"
In Supabase I can filter like this:
let { data: stores } = await supabase
.from('stores')
.select("*")
.eq('name', 'Ford car shop')
// Returns
{
id: 123456,
car:"Ford",
name:"Ford car shop"
}
or join like this:
let { data: stores } = await supabase
.from('stores')
.select(`
*,
cars (
brand
)
`)
.eq('name', 'Ford car shop')
// Returns
{
id: 123456,
car:"Ford",
cars: {
id: 654321,
brand: "Ford"
}
name:"Ford car shop"
}
But how can I filter stores by the brand of the car they carry using the supabase sdk?
2022: This is now possible with supabase client. You can use the !inner() function.
let { data: stores } = await supabase
.from('stores')
.select('*, cars!inner(*)')
.eq('cars.brand', 'Ford')
Doc here: Filtering with inner joins
You can use the built in postgrest api supabase gives you to get this info. e.g:
/projects?select=*,clients!inner(*)&clients.id=eq.12
this isn't added to the supabase client yet.
the patch is shown here: https://github.com/PostgREST/postgrest/releases/tag/v9.0.0
Edit:
Supabase recently added this feature. The new accepted answer is below.
I did some more research and found out that this is currently not possible. However, it seems like it has been implemented and will make it into the next Supabase release.
An interim solution is using views and then querying those.
CREATE VIEW stores_expanded AS
SELECT
stores.id,
stores.name,
cars.brand
FROM
stores
LEFT JOIN cars
ON
stores.car = cars.id;
let { data: stores } = await supabase
.from('stores')
.select("*")
.eq('brand', 'x')

How to insert a username if it doesn't already exist with a postgresql POOL query

I am making a game and I recently added a server database score saver but I can't figure out how to insert a username only if it doesn't already exist here is the following query:
const addUser = (req, res) => {
const {username, score} = req.body;
pool.query(
'INSERT INTO userlist (username, score) VALUES ($1, $2)',
[username, score],
(err) => {
if(err){
throw err;
}
res.status(201).json({status: "success", message: "User added."});
},
);
}
I am guessing I'll have to change the query
also here is my SQL code for creating the table:
CREATE TABLE userlist(
ID SERIAL PRIMARY KEY,
username VARCHAR(255),
score VARCHAR(255)
);
The best way to handle this is to let the database validate the uniqueness of the username:
alter table userlist add constraint unq_userlist_usename unique(username);
Now if you attempt to insert a single row, then it will return an error if the row already exists.
If you don't want an error you can use an on conflict clause. However, in this case, an exception seems useful to notify the user that username already exists.
use an if statement to identify if the username exist and then update it
if (Users::where('name', $request->user_name)->exists()) {
return response()->json(['record exist']);
} else {
$save = new Users;
$save->name = $request->user_name;
$save->save();
return response()->json(['User saved successfully.']);
}

Dealing with collections in SQL

I have this table in which I want to register likes from users. The data type for likes is an array. INT[] I don't know if this is the best approach to handle like and unlike
I have not found an effective way to manipulate collection in order to toggle like/unlike from a user.
can we use sthg like an associative array in SQL? or, what would be the best approach with an array ? I could not find one example.
Thks for pointing me in the right direc†ion.
CREATE TABLE posts (
pid SERIAL PRIMARY KEY,
user_id INT REFERENCES users(uid),
author VARCHAR REFERENCES users(username),
title VARCHAR(255),
content TEXT,
date_created TIMESTAMP,
like_user_id INT[] DEFAULT ARRAY[]::INT[],
likes INT DEFAULT 0
);
const likePost = (req, res, next) => {
const values = [req.body.id, req.body.user_id];
console.log(values);
const query = `UPDATE posts SET likes = likes - 1 WHERE pid = $1, UPDATE posts SET likes[1] = $2 WHERE pid = $1`;
pool.query(query, values, (q_err, q_res) => {
if (q_err) return next(q_err);
res.json(`post ${req.body.id} succcessfully remove 👍`);
});
};

NODE JS Passing characters in get request

I am using Node and Express with MSNODESQLV8 to write an API demo (my first) to get some rows from a remote SQL Server instance. My other get queries work fine when searching for an ID which is a number but I am unsure how to pass a value in the form of characters to a parameter in my query. Pretty sure req.params.id is not appropriate.
app.get("/productsname/:id", (req, res) => {
const productName = req.params.id;
const productsNameQuery = "SELECT * FROM Products WHERE ProductName = ?";
sql.query(connStr, productsNameQuery, [productName], (err, rows) => {
if (err) {
console.log(`Failed to get product by id ${req.params.id}. ${err}`);
res.sendStatus(500);
}else {
res.json(rows);
}
})
});
I want to take a product name (string?) in at the end of the url where it reads "id" and pass it as a value to the productName const. The end goal is to retrieve all rows from the SQL table where the product name is "processor" in the get url (http://localhost:2000/productname/proccesor). Perhaps I am passing the url incorrectly?
Apologies if this is really basic. I am very new to this.
Thanks in advance