How to format PostgreSQL jsonb_set as a prepared statement - postgresql

var query=`UPDATE "public"."vehicle_ads"
SET options=
jsonb_set(
options,
'{$1, ${subgroup}, -1}',
'{"name": "${optionName}"}'::jsonb
)
WHERE "vehicleId"=${id}`;
I'm having the following issues with the above query. If I replace $1 with ${group}, no error. But if I leave $1 and pass group as a prepared statement, I get the error...
bind message supplies 1 parameters, but prepared statement "" requires 0
My goal is to tokenize the entire query, e.g.:
var query=`UPDATE "public"."vehicle_ads"
SET options=
jsonb_set(
options,
'{$1, $2, -1}',
'{"name": $3}'::jsonb
)
WHERE "vehicleId"=$4`;
Then...
could not determine data type of parameter $1
I know I'm lost in a formatting soup of template strings and Postgres, unsure what needs ticks, single quotes, or double. Any help is greatly appreciated.
EDIT:
Here's what I'm doing with detail.
I have a nested object with vehicle options data stored as a jsonb field. It has the form:
{
"Group": {
"SubGroup": [
{
"name": string,
"hasOption": bool
}
...
]
...
}
...
}
I want to edit the name in a sub group. For instance Powertrain.Drivetrain[0].name='AWD';

You'll have to convert the variable to text before converting it to jsonb using to_jsonb
UPDATE table SET body = jsonb_set(options, '{key}', to_jsonb($1::text));

Related

How to translate/convert a Postgresql IN query as variable and send the variable using Golang and SQLC with a proper struct?

First of all, if someone has a better sentence for my question, feel free to comment.
I want to translate this query into Golang
SELECT
mou."id",
mou."name",
mou.description,
mou.img_url,
um.favorite
FROM
majors_of_universities mou
JOIN field_of_studies fos ON mou.field_of_studies_id = fos."id"
JOIN univ_major um ON mou."id" = um.majors_of_universities_id
WHERE
mou."name" ILIKE '%%'
AND fos."name" IN ( 'IT & Software', 'Analisis Data & Statistik' )
ORDER BY
mou."name"
LIMIT 99 OFFSET 0;
This query works well, btw. I'm using sqlc as a generator and by it rules (CMIIW), I changed...
'%%' to $1
'IT & Software', 'Analisis Data & Statistik' to $2
99 to $3
0 to $4
so it become a variable.
little did I know, the $2 generated into a string data type. what I want is it generated into an array of string data type, because I found out that Golang can translate an array of string from ["1", "2", "3"] into '1', '2', '3' , just like what I want to input inside postgres IN parenthesis.
in Golang side, I made a custom struct like this
type SearchMajorReq struct {
Name string `json:"name"`
FieldOfStudies []string `json:"field_of_studies"`
Limit int32 `json:"limit"`
Page int32 `json:"page"`
}
in hope that this is the correct data type to send a JSON req body like this
{
"name":"",
"field_of_studies": ["1", "2", "3"],
"limit": 10,
"page": 1
}
but it doesn't works. I have an error in FieldOfStudies part.
How can I solve this?

Postgres jsonb_set concatenate current value

I'm trying to use jsonb_set to update a range of json objects within my database. I can get a query working that updates the object with a string value, however I cannot seem to get it to update using the current value.
UPDATE entity
SET properties = jsonb_set(properties, '{c_number}', concat('0', properties->>'c_number'))
WHERE type = 1 and length(properties->>'c_number') = 7
The above doesn't work in its current format, I think the issue is the properties->>'c_number' inside the jsonb_set. Is there a way I can access the current value and simply add a leading 0?
Found a solution:
UPDATE entity
SET properties = jsonb_set(properties, '{c_number}', concat('"0', properties->>'c_number', '"')::jsonb)
WHERE type = 1 and length(properties->>'c_number') = 7
Based on this answer I was able to prepare my solution.
My goal was to create a new property in JSON, with a value that is based on the value of one of the properties which my JSON already has.
For example:
I have:
{
property_root: { property_root_child: { source_property_key: "source_property_value" } }
}
I want:
{
property_root: { property_root_child: { source_property_key: "source_property_value", target_property_key: "source_property_value + my custom ending" } }
}
So my query would look:
UPDATE database.table_with_json
SET json_column=jsonb_set(
json_column,
'{ property_root, property_root_child, target_property_key }',
concat('"', json_column->'property_root'->'property_root_child'->>'source_property_key', ' + my custom ending', '"')::jsonb)
WHERE
json_column->'property_root'->'property_root_child'->'source_property_key' IS NOT NULL
Why concat looks messy? Based on the answer mentioned above:
The third argument of jsonb_set() should be of jsonb type. The problem is in casting a text string to jsonb string, you need a string in double quotes.
That is why we have to wrap concat in double qoutes.

how to convert map<anydata> to json

In my CRUD Rest Service I do an insert into a DB and want to respond to the caller with the created new record. I am looking for a nice way to convert the map to json.
I am running on ballerina 0.991.0 and using a postgreSQL.
The return of the Update ("INSERT ...") is a map.
I tried with convert and stamp but i did not work for me.
import ballerinax/jdbc;
...
jdbc:Client certificateDB = new({
url: "jdbc:postgresql://localhost:5432/certificatedb",
username: "USER",
password: "PASS",
poolOptions: { maximumPoolSize: 5 },
dbOptions: { useSSL: false }
}); ...
var ret = certificateDB->update("INSERT INTO certificates(certificate, typ, scope_) VALUES (?, ?, ?)", certificate, typ, scope_);
// here is the data, it is map<anydata>
ret.generatedKeys
map should know which data type it is, right?
then it should be easy to convert it to json like this:
{"certificate":"{certificate:
"-----BEGIN
CERTIFICATE-----\nMIIFJjCCA...tox36A7HFmlYDQ1ozh+tLI=\n-----END
CERTIFICATE-----", typ: "mqttCertificate", scope_: "QARC", id_:
223}"}
Right now i do a foreach an build the json manually. Quite ugly. Maybe somebody has some tips to do this in a nice way.
It cannot be excluded that it is due to my lack of programming skills :-)
The return value of JDBC update remote function is sql:UpdateResult|error.
The sql:UpdateResult is a record with two fields. (Refer https://ballerina.io/learn/api-docs/ballerina/sql.html#UpdateResult)
UpdatedRowCount of type int- The number of rows which got affected/updated due to the given statement execution
generatedKeys of type map - This contains a map of auto generated column values due to the update operation (only if the corresponding table has auto generated columns). The data is given as key value pairs of column name and column value. So this map contains only the auto generated column values.
But your requirement is to get the entire row which is inserted by the given update function. It can’t be returned with the update operation if self. To get that you have to execute the jdbc select operation with the matching criteria. The select operation will return a table or an error. That table can be converted to a json easily using convert() function.
For example: Lets say the certificates table has a auto generated primary key column name ‘cert_id’. Then you can retrieve that id value using below code.
int generatedID = <int>updateRet.generatedKeys.CERT_ID;
Then use that generated id to query the data.
var ret = certificateDB->select(“SELECT certificate, typ, scope_ FROM certificates where id = ?”, (), generatedID);
json convertedJson = {};
if (ret is table<record {}>) {
var jsonConversionResult = json.convert(ret);
if (jsonConversionResult is json) {
convertedJson = jsonConversionResult;
}
}
Refer the example https://ballerina.io/learn/by-example/jdbc-client-crud-operations.html for more details.?

Sails ORM: How to pass value with array in valuesToEscape parameter

I've rawQuery which requires comma separated string but according to the documentation here, the second argument should be an array:
An array of dynamic, untrusted strings to SQL-escape and inject within the SQL string using the appropriate template syntax for this model's database. (If you have no dynamic values to inject, then just use an empty array here.)
var rawQuery = 'SELECT * FROM "user" WHERE "user"."email" IN ($1)';
User.query(rawQuery, ['a#a.com', 'b#b.com'], function (err, rawResult) {
if (err) { return res.serverError(err); }
return res.ok(rawResult.rows);
});
How can I make this query work without passing a variable through an array? I can directly add the variable like this
var rawQuery = 'SELECT * FROM "user" WHERE "user"."email" IN (' + foo +')';
But it will be prone to SQL injection attack.
To run the query directly without using the parameter injection mode, you need to remove SQL command especial characters, otherwise you will be prune to injection attacks, as you said.
There are packages that do that for you:
the most popular are npm: sql-escape and npm sqlstring
They will add escape characters to any especial character into your string:
var escape = require('sql-escape');
var result = escape('my sweet "string"');
//result: 'my sweet \\"string\\"'

Updating an array of objects fields in crate

I created a table with following syntax:
create table poll(poll_id string primary key,
poll_type_id integer,
poll_rating array(object as (rating_id integer,fk_user_id string, israted_image1 integer, israted_image2 integer, updatedDate timestamp, createdDate timestamp )),
poll_question string,
poll_image1 string,
poll_image2 string
)
And I inserted a record without "poll_rating" field which is actually an array of objects fields.
Now when I try to update a poll_rating with the following commands:
update poll set poll_rating = [{"rating_id":1,"fk_user_id":-1,"israted_image1":1,"israted_image2":0,"createddate":1400067339.0496}] where poll_id = "f748771d7c2e4616b1865f37b7913707";
I'm getting an error message like this:
"SQLParseException[line 1:31: no viable alternative at input '[']; nested: ParsingException[line 1:31: no viable alternative at input '[']; nested: NoViableAltException;"
Can anyone tell me why I get this error when I try to update the array of objects fields.
Defining arrays and objects directly in SQL statement is currently not supported by our SQL parser, please use parameter substitution using placeholders instead as described here:
https://crate.io/docs/current/sql/rest.html
Example using curl is as below:
curl -sSXPOST '127.0.0.1:4200/_sql?pretty' -d#- <<- EOF
{"stmt": "update poll set poll_rating = ? where poll_id = ?",
"args": [ [{"rating_id":1,"fk_user_id":-1,"israted_image1":1,"israted_image2":0,"createddate":1400067339.0496}], "f748771d7c2e4616b1865f37b7913707" ]
}
EOF