Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert PSQLs ::json @> ::json to a jpa/jpql-predicate

Say i have a db-table looking like this:

CREATE TABLE myTable(
   id BIGINT, 
   date TIMESTAMP, 
   user_ids JSONB 
);

user_ids are a JSONB-ARRAY

Let a record of this table look like this:

{
     "id":13,
     "date":"2019-01-25 11:03:57",
     "user_ids":[25, 661, 88]
};

I need to query all records where user_ids contain 25. In SQL i can achieve it with the following select-statement:

SELECT * FROM myTable where user_ids::jsonb @> '[25]'::jsonb;

Now i need to write a JPA-Predicate that renders "user_ids::jsonb @> '[25]'::jsonb" to a hibernate parseable/executable Criteria, which i then intent to use in a session.createQuery() statement. In simpler terms i need to know how i can write that PSQL-snippet (user_ids::jsonb @> '[25]'::jsonb) as a HQL-expression.

like image 881
INeedHelp Avatar asked Oct 17 '25 08:10

INeedHelp


2 Answers

Fortunately, every comparison operator in PostgreSQL is merely an alias to a function, and you can find the alias through the psql console by typing \doS+ and the operator (although some operators are considered wildcards in this search, so they give more results than desired).

Here is the result:

postgres=# \doS+ @>
                                          List of operators
   Schema   | Name | Left arg type | Right arg type | Result type |      Function       | Description 
------------+------+---------------+----------------+-------------+---------------------+-------------
 pg_catalog | @>   | aclitem[]     | aclitem        | boolean     | aclcontains         | contains
 pg_catalog | @>   | anyarray      | anyarray       | boolean     | arraycontains       | contains
 pg_catalog | @>   | anyrange      | anyelement     | boolean     | range_contains_elem | contains
 pg_catalog | @>   | anyrange      | anyrange       | boolean     | range_contains      | contains
 pg_catalog | @>   | box           | box            | boolean     | box_contain         | contains
 pg_catalog | @>   | box           | point          | boolean     | box_contain_pt      | contains
 pg_catalog | @>   | circle        | circle         | boolean     | circle_contain      | contains
 pg_catalog | @>   | circle        | point          | boolean     | circle_contain_pt   | contains
 pg_catalog | @>   | jsonb         | jsonb          | boolean     | jsonb_contains      | contains
 pg_catalog | @>   | path          | point          | boolean     | path_contain_pt     | contains
 pg_catalog | @>   | polygon       | point          | boolean     | poly_contain_pt     | contains
 pg_catalog | @>   | polygon       | polygon        | boolean     | poly_contain        | contains
 pg_catalog | @>   | tsquery       | tsquery        | boolean     | tsq_mcontains       | contains
(13 rows)

What you want is jsonb arguments on both sides, and we see the function that has that is called jsonb_contains. So the equivalent to jsonbcolumn @> jsonbvalue is jsonb_contains(jsonbcolumn, jsonbvalue). Now you can't use the function in either JPQL or CriteriaBuilder, unless you register it through a custom Dialect if you're using Hibernate. If you're using EclipseLink, I don't know the situation there.

From here on, your options are to use native queries, or add your own Hibernate Dialect by extending an existing one.

like image 112
coladict Avatar answered Oct 19 '25 08:10

coladict


Replacing "@>" with "jsonb_contains()" is not a good idea. The operator is indexed, not the function. Example: https://dbfiddle.uk/-xMuHYAA

like image 25
FranckPachot Avatar answered Oct 19 '25 08:10

FranckPachot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!