Postgres - Query for nested value in nested array - postgresql

I have a table called clients with a column called configs containing JSON object.
{
"pos_link": {
"primary_id": "000123",
"sub_ids": ["000123", "000124", "00125", "000126"],
},
"prime_tags": {
"tags": ["Children"]
}
}
How do I find all entries where one of the sub_id is '00124'
select *
from clients c,
jsonb_array_elements(c.configs->'pos_link') pos_link,
jsonb_array_elements(pos_link->'sub_ids') sub_ids
where sub_id IN ('00124')

You can use the contains operator ?
select *
from clients
where configs -> 'pos_link' -> 'sub_ids' ? '000124';
This assumes that configs is defined as jsonb (which it should be). If it's not, you need to cast it: configs::jsonb
Online example

Related

How to bind an array to a parameter used alongside IN operator in sequelize query

I had to write a custom postgres sql query, so I used sequelize.query method. But I am a bit lost in how I can bind an array to a parameter used alongside an IN operator. The current code looks something like this, with obviously doesn't work.
sequelize.query('SELECT * FROM students WHERE grade IN $grades', {
bind: { grades: ['A+', 'A'] },
type: sequelize.QueryTypes.SELECT,
});
Use = any instead of in. Change the query text to
SELECT * FROM students WHERE grade = any(string_to_array($grades, ','))
or
SELECT * FROM students WHERE grade = any(('{'||$grades||'}')::text[])
and bind grades as a string, 'A+,A'.
The second option works for other data types too.

Using index for jsonb sub keys postgresql

I have a table like:
create table items
(
id int constraint items_pk primary key,
acl jsonb
);
With such items:
id,acl
1,{
"users": {
"2": { <-- The key "2" is the user_id
"role1": {...},
"role2": {...}
},
"3": {
"role1": {...}
}
},
"groups": {...}
}
...
I want to count the number of items where the user "2" has the role "role2", what I do:
SELECT COUNT(*) FROM items WHERE ( acl->'users'->'2' ? 'role2')
The problem is that I want this query to use an index, but I can't make this query to use them. Here are the index I setup:
CREATE INDEX _index1 ON items using gin (acl jsonb_ops);
CREATE INDEX _index2 ON items using gin ((acl->'users') jsonb_ops);
Then I tried this query that is using the index but it is slower ( like 40x ) than the first one so it is unuseful. And also goes beyond the fact that I just want to verify the presence of the "role2" key in acl->'users'->'2'.
SELECT COUNT(*) FROM items WHERE ( acl #> '{"users": {"2": {"role2": {...}}}}');
My question is how can I make this query to use an index keeping my current json data structure ?
I know I can use string arrays and lots of other things to make this usecase work but they imply changing the data structure, and this is not my point here because the problem is that this data structure is used at scale and I want to know if something is possible with this structure.

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.?

How to return a plain value from a Knex / Postgresql query?

I'm trying to return a simple, scalar string value from a Postgres DB using Knex. So far, everything I do returns a JSON object with a key (the column name) and the value, so I have to reach into the object to get the value. If I return multiple rows, then I get multiple JSON objects, each one repeating the key.
I could be returning multiple columns, in which case each row would at least need to be an array. I'm not looking for a special case where specifying a single column returns the value without the array -- I'm OK reaching into the array. I want to avoid the JSON object with the repetitive listing of column names as keys.
I've scoured the Knex docs but don't see how to control the output.
My table is a simple mapping table with two string columns:
CREATE TABLE public._suite
(
piv_id character(18) NOT NULL,
sf_id character(18) NOT NULL,
CONSTRAINT _suite_pkey PRIMARY KEY (piv_id)
)
When I build a query using Knex methods like
let myId = 'foo', table = '_suite';
return db(table).where('piv_id', myId).first(['sf_id'])
.then( function(id) { return(id); });
I get {"sf_id":"a4T8A0000009PsfUAE"} ; what I want is just "a4T8A0000009PsfUAE"
If I use a raw query, like
return db.raw(`select sf_id from ${table} where piv_id = '${myId}'`);
I get a much larger JSON object describing the result:
{"command":"SELECT","rowCount":1,"oid":null,"rows":[{"sf_id":"a4T8A0000009Q9HUAU"}],"fields":[{"name":"sf_id","tableID":33799,"columnID":2,"dataTypeID":1042,"dataTypeSize":-1,"dataTypeModifier":22,"format":"text"}],"_parsers":[null],"RowCtor":null,"rowAsArray":false}
What do I have to do to just get the value itself? (Again, I'm OK if it's in an array -- I just don't want the column names.)
Take a look at the pluck method.
db(table).where('piv_id', myId).pluck('sf_id'); // => will return you ["a4T8A0000009PsfUAE"]

GORM for MongoDB: Derived Property?

I am trying to build a criteria of comparing the value of a derived property of adding two fields as shown in
Can I do a math operation inside a createCriteria, i.e.
class SumFormula {
Integer column1
Integer column2
Integer sum
static mapping = {
sum formula: 'column1 + column2'
}
}
and the criteria:
SumFormula.createCriteria().list() {
ne("sum", 100)
}
However I could not make it work with MongoDB. The derived property is always null when printed out.
The above cited post did mention that derived properties are SQL expressions, so the questions is that are the derived properties only available with GORM for SQL? Any alternative for GORM for MongoDB?
derived properties are a Hibernate/SQL specific feature and are not supported in GORM for MongoDB. An alternative is to simply do this in code:
class SumFormula {
Integer column1
Integer column2
Integer getSum() { column1 + column2 }
}
We are facing the same problem. Currently, our workaround is to actually store the derived properties in MongoDB and use the beforeUpdate methods to calculate the values.
def beforeUpdate() {
sum = column1 + column2
}