Node-postgres parameterized query for INSERT INTO if not exists - node.js

I have a working parameterized query for an insert statement but I now want to add in a 'WHERE NOT EXISTS' clause. The working insert looks like this:
pgClient.query("INSERT INTO social_posts (username, user_image, message, image_url, post_id, post_url, location, network) VALUES ($1,$2,$3,$4,$5,$6,$7,$8)", postArray,
function(err, result) {...}
What I'd like to implement is:
pgClient.query("INSERT INTO social_posts(username, user_image, message, image_url, post_id, post_url, location, network) SELECT ($1,$2,$3,$4,$5,$6,$7,$8) WHERE NOT EXISTS (SELECT 1 FROM social_posts WHERE post_id = $9)", postArray,
function(err, result) {...}
In this case the $9 would actually be equal to postArray[4].
I've tried pushing the value into the array again, that didn't work:
error running query { [error: operator does not exist: character varying = bigint]
name: 'error',
length: 207,
severity: 'ERROR',
code: '42883',
detail: undefined,
hint: 'No operator matches the given name and argument type(s). You might need to add explicit type casts.',
position: '198',
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'parse_oper.c',
line: '722',
routine: 'op_error' }
I tried interpolating the value, that didn't work:
error running query { [error: there is no parameter $1]
name: 'error',
length: 88,
severity: 'ERROR',
code: '42P02',
detail: undefined,
hint: undefined,
position: '114',
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'parse_expr.c',
line: '823',
routine: 'transformParamRef' }
Does anyone have any ideas? Thanks in advance!

After doing some research I came across something helpful here. I couldn't get the $9 parameter to work the reason why it wouldn't work with interpoloation had to do with an extra set of parentheses around the SELECT items. The correct syntax is:
var postID = postArray[4].toString() // per joop's comment above
pgClient.query("INSERT INTO social_posts(username, user_image, message, image_url, post_id, post_url, location, network) SELECT $1,$2,$3,$4,$5,$6,$7,$8 WHERE NOT EXISTS (SELECT 1 FROM social_posts WHERE post_id = '" + postId + "')", postArray,
function(err, result) {...}

Related

Why am I getting error: null value in column when inserting into a table?

I have two tables in postgresql, as follows:
User Table:
CREATE TABLE public.users
(
user_id integer NOT NULL DEFAULT nextval('users_user_id_seq'::regclass),
first_name character varying(90) COLLATE pg_catalog."default" NOT NULL,
last_name character varying(90) COLLATE pg_catalog."default" NOT NULL,
email citext COLLATE pg_catalog."default" NOT NULL,
user_password character varying(90) COLLATE pg_catalog."default" NOT NULL,
business_status boolean NOT NULL,
phone_number character varying(12) COLLATE pg_catalog."default" NOT NULL,
bt_id integer,
bs_id integer,
is_active boolean NOT NULL,
is_verified boolean NOT NULL,
CONSTRAINT users_pkey PRIMARY KEY (user_id),
CONSTRAINT users_email_key UNIQUE (email),
CONSTRAINT bs_id FOREIGN KEY (bs_id)
REFERENCES public.business_step (bs_id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE CASCADE
NOT VALID,
CONSTRAINT bt_id FOREIGN KEY (bt_id)
REFERENCES public.business_type (bt_id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE CASCADE
NOT VALID
)
Admin Table:
CREATE TABLE public.admin
(
admin_id integer NOT NULL DEFAULT nextval('admin_admin_id_seq'::regclass),
user_id integer NOT NULL,
CONSTRAINT admin_pkey PRIMARY KEY (admin_id),
CONSTRAINT user_id FOREIGN KEY (user_id)
REFERENCES public.users (user_id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE CASCADE
)
I am using Nodejs to implement a route in which I can insert a new administrator with the following code:
Code in Queries.js
const insertAdmin = (request, response) => {
const { user_id } = request.body
pool.query('INSERT INTO admin (user_id) VALUES ($1)', [user_id], (error, results) => {
if (error) {
throw error
}
response.status(201).send(`User added with ID: ${result.insertId}`)
})
}
Code in index.js
app.post('/admins/insert', db.insertAdmin)
When inserting a new administrator using the following curl route:
curl --data "user_id =39" http://localhost:3000/users
I am getting the following error message:
error: null value in column "user_id" of relation "admin" violates not-null constraint
at Parser.parseErrorMessage (C:\Users\ealfo\node-api-postgres\node_modules\pg-protocol\dist\parser.js:278:15)
at Parser.handlePacket (C:\Users\ealfo\node-api-postgres\node_modules\pg-protocol\dist\parser.js:126:29)
at Parser.parse (C:\Users\ealfo\node-api-postgres\node_modules\pg-protocol\dist\parser.js:39:38)
at Socket. (C:\Users\ealfo\node-api-postgres\node_modules\pg-protocol\dist\index.js:10:42)
at Socket.emit (events.js:315:20)
at addChunk (_stream_readable.js:309:12)
at readableAddChunk (_stream_readable.js:284:9)
at Socket.Readable.push (_stream_readable.js:223:10)
at TCP.onStreamRead (internal/stream_base_commons.js:188:23) {
length: 265,
severity: 'ERROR',
code: '23502',
detail: 'Failing row contains (12, null).',
hint: undefined,
position: undefined,
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: 'public',
table: 'admin',
column: 'user_id',
dataType: undefined,
constraint: undefined,
file: 'd:\pginstaller_13.auto\postgres.windows-x64\src\backend\executor\execmain.c',
line: '1965',
routine: 'ExecConstraints'
}
Why does this error message appears? I am new at using NodeJS and PostgreSQL, I apologize if this question has been answered in another post. Nonetheless, I would like to learn more and learn from my mistakes. Thank you in advance.
You will have to add body-parser to your middleWare. Judging by the curl command you will need to parse the body from url.
Something like.
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true })); // to pass bodies from url
Full documentation of body-parser library can be found: https://github.com/expressjs/body-parser

PostgreSQL throws error "function count(integer) does not exist" with massivejs & node, but works with Postico

I'm working on a web app using React, Node, Express, Massive, and PostgreSQL, and having trouble performing one specific query:
SELECT
COUNT(DISTINCT cu.user_id) AS ucount,
COUNT(DISTINCT p.project_id) AS pcount,
COUNT(DISTINCT t.task_id) AS tcount,
c.clique_id, c.clique_name, c.admin_id, c.created_on
FROM cliques c
FULL OUTER JOIN cliques_users cu ON cu.clique_id = c.clique_id
FULL OUTER JOIN users u ON u.user_id = cu.user_id
FULL OUTER JOIN projects p ON p.clique_id = cu.clique_id
FULL OUTER JOIN tasks t ON t.clique_id = cu.clique_id
WHERE c.clique_id IN (
SELECT cu.clique_id FROM cliques_users cu WHERE cu.user_id = 3
)
GROUP BY c.clique_id;
**Note: I'm using 3 on the subquery just to test.
I'm using Postico to test my SQL statements, and this query returns the results I expect. But when this is done on the app itself, requesting the data by hitting an endpoint, the server throws an error:
{ error: function     count(integer) does not exist at ...
name: 'error',
length: 225,
severity: 'ERROR',
code: '42883',
detail: undefined,
hint: 'No function matches the given name and argument types. You might need to add explicit type casts.',
position: '55',
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'parse_func.c',
line: '528',
routine: 'ParseFuncOrColumn' }
The callback function that runs when the endpoint is hit looks like this:
(req, res, next) => {
req.app.get( 'db' )
.clique.getCliqueSummaryQuery( req.params.user_id )
.then( response => {
res.status(200).json(response);
})
.catch( err => {
console.log( 'getMyCliquesInfo failed: ', err );
res.status(500).json( err );
});
}
getCliqueSummaryQuery() runs the query, passing a url parameter as a variable that will replace the 3 I've hardcoded for testing. The error occurs with both variable and hardcoded values. I've copied the query straight from Postico to my sql file.
Anyone know why it works one way and not the other?

How to use ID in Query in BookshelfJS?

I have one field & it has comma separated ID, so i want to find from that selected id, here is my code,
.get(function(req, res) {
knex.select('*')
.from('exam')
.whereRaw('? = any(regexp_split_to_array(student_id))', [req.params.id])
.then(function(rows) {
//return res.send(rows);
console.log(rows);
})
.catch(function(error) {
console.log(error)
});
});
===> while i am using KNEX it will give an Error Like this,
{ error: function regexp_split_to_array(text) does not exist
name: 'error',
length: 220,
severity: 'ERROR',
code: '42883',
detail: undefined,
hint: 'No function matches the given name and argument types. You might need to add explicit type casts.',
position: '37',
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'parse_func.c',
line: '523',
routine: 'ParseFuncOrColumn'
}
in student_id column i have ID like this, 33,34,35,36
in req.params.id i got only one single ID like, 35.
so i want that rows which have included 35 ID, in Same Table.
===> So i want Only Two Rows (2,3) because it has Included ID = 35.
Assuming you are using PostgreSQL database (I saw you use phpPgAdmin on the screenshot). You can use regexp_split_to_array function to convert your string to array (obviously :). And the perform search over the resulting array using any.
In SQL words, it can be written like this
select '35' = any(regexp_split_to_array('33,34,35,36', E','));
In your query, you can replace .where with
.whereRaw("? = any(regexp_split_to_array(student_id, E','))", [req.params.id])
But keep in mind, this can be performance-heavy request, as for each row you execute string split operation. A better way of doing this (assuming it is necessary for your project to contain array values in one row) is to store your student_id in the Array type and add gin index on student_id column and perform search operations like this
select * from table where student_id #> '{35}';

Redshift - unsupported type "serial" for auto increment id with node-orm-2

Any insight on how to get an auto increment id working? From my understanding, an id column is added by default; however, because I'm using Redshift, the default "serial" type won't work as it is not supported.
{ [error: Column "probe.id" has unsupported type "serial".]
name: 'error',
length: 165,
severity: 'ERROR',
code: '0A000',
detail: undefined,
hint: undefined,
position: undefined,
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: '/home/awsrsqa/padb/src/pg/src/backend/parser/parser_analyze.c',
line: '3600',
routine: 'transformColumnDefinition',
model: 'probe' }
No such thing supported.
You can only get an auto-increment for an integer:
IDENTITY(seed, step)
Clause that specifies that the column is an IDENTITY column. An IDENTITY column contains unique auto-generated values. These values start with the value specified as seed and increment by the number specified as step. The data type for an IDENTITY column must be either INT or BIGINT.
For a GUID you will have to generate one and insert it yourself.
Example:
CREATE TABLE your_table(
id INT IDENTITY(1, 1)
);

node-postgres: parameterised insert query cached, failing on 2nd run

I'm trying to run two parameterised insert queries using node-postgres: the first one specifies the primary key column, the second doesn't.
The second query, even though doesn't specify the primary key column, fails saying there's a duplicate primary key.
My pg table:
CREATE TABLE teams (
id serial PRIMARY KEY,
created_by int REFERENCES users,
name text,
logo text
);
Code that reproduces this issue:
var pg = require('pg');
var insertWithId = 'INSERT INTO teams(id, name, created_by) VALUES($1, $2, $3) RETURNING id';
var insertWithoutId = 'INSERT INTO teams(name, created_by) VALUES($1, $2) RETURNING id';
pg.connect(process.env.POSTGRES_URI, function (err, client, releaseClient) {
client.query(insertWithId, [1, 'First Team', 1], function (err, result) {
releaseClient();
if (err) {
throw err;
}
console.log('first team created');
});
});
pg.connect(process.env.POSTGRES_URI, function (err, client, releaseClient) {
client.query(insertWithoutId, ['Second Team', 1], function (err, result) {
releaseClient();
if (err) {
console.log(err);
}
});
});
And output of running this:
first team created
{ [error: duplicate key value violates unique constraint "teams_pkey"]
name: 'error',
length: 173,
severity: 'ERROR',
code: '23505',
detail: 'Key (id)=(1) already exists.',
hint: undefined,
position: undefined,
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: 'public',
table: 'teams',
column: undefined,
dataType: undefined,
constraint: 'teams_pkey',
file: 'nbtinsert.c',
line: '406',
routine: '_bt_check_unique' }
What I gather from reading the node-postgres source, parameterised queries are treated as prepared queries, which get cached if they reuse a name parameter; though from digging around it's source, it doesn't seem to think that my queries have a name property.
Does anyone have any ideas on how this could be avoided?
The first insert supplies a value for id, so the serial is not incremented. The serial still is 1 after the first insert. The second insert does not supply a value for id, so the serial (=1) is used. Which is a duplicate. Best solution is to only use the second statement, and let the application use the returned id, if needed.
In short: don't interfere with serials.
If you need to correct the next value for a sequence, you can use something like the below statement.
SELECT setval('teams_id_seq', (SELECT MAX(id) FROM teams) )
;

Resources