Spring-Data-JPA native query on jsonb field - postgresql

Given the following JSON which is stored as jsonb in a postgres table:
{
"object" : {
"array" [
{
"uuid" : "34ad3558-a3e7-43d0-826f-afddce255b20"
}
]
}
}
I have a working query to search if a field value is present within the JSON document:
select * from my_table
where my_json#>'{"object": {"array" : [{"field": "34ad3558-a3e7-43d0-
826f-afddce255b20"}]}}';
However when I try to replicate this query in Spring-Data-JPA using a native query on a JPARepository I keep getting the following exception:
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter with that position [1] did not exist
I initally tried:
#Query(value = "Select * From my_table"
+ "and my_json#>'{\"object\": {\"array\" : [{\"uuid\": \"?1\"}]}}'",
nativeQuery = true)
Set<MyEntity> myQuery(UUID uuid);
Following this I tried binding the parameter with #Param :
#Query(value = "Select * From my_table"
+ "and my_json#>'{\"object\"\\: {\"array\" \\: [{\"uuid\"\\: \":uuid\"}]}}'",
nativeQuery = true)
Set<MyEntity> myQuery(#Param("uuid") UUID uuid);
After that I tried converting the UUID to a String:
#Query(value = "Select * From my_table"
+ "and my_json#>'{\"object\"\\: {\"array\" \\: [{\"uuid\"\\: \":uuid\"}]}}'",
nativeQuery = true)
Set<MyEntity> myQuery(#Param("uuid") String uuid);
Still nothing works. The JPA entity looks like this :
#Entity
public class MyEntity {
#Id
private long id;
#Column("my_json")
private MyJson myJson
}
Other queries that invole the entity work fine with the jsonb field binding to MyJson entity. Is there a way to make this work?

You have to cast the value in your native query.
cast(:uuid as UUID)
So your query becomes.
#Query(value = "Select * From my_table"
+ "and my_json#>'{\"object\"\\: {\"array\" \\: [{\"uuid\"\\: cast(:uuid as UUID)}]}}'",
nativeQuery = true)

Related

Passing an string parameter in JPQL native query

I have the following JpaRepository method:
#Query(value = "select * from default_price_view where product_code #> '{:productCode}'", nativeQuery = true)
Page<DefaultPriceView> findDefaultPricesByProductCode(Pageable pageable,
#Param("productCode") String productCode);
product_code is an array of strings with the format in Postgresql:
{021715,X91778,W21722}
Can you please tell me how I could add the parameter productCode into the query because currently it doesn't work :-(
Thank you in advance for your help,
If I understand well you have product_code is an array in Java, and in Postgresql it's with this format {021715,X91778,W21722}
If this is the case, Try to define a string :
String productCodeString = "{" + productCode[0] + "," + productCode[1]+ "," +productCode[2]+ "}";
and use it in your request :productCodeString

How to JPA Query for Postgresql #Type list-array?

I have column in a database in which data are stored in this way {type1,type2,...}. I want to get elements from CARS table which are in Set carTypes.
#Type(type = "list-array")
#Column(name = "TYPES")
private final List<String> types;
Not working:
#Query("SELECT * FROM cars c WHERE (:carTypes) IN (c.types)")
List<Object[]> findCars(#Nullable #Param("carTypes") Set<String> carTypes);
Error:
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: bytea = character varying[]
I don't know what the Spring Data abstraction for this (or if there is any), but with plain Hibernate you can do something like this:
BasicType type = (BasicType) session.getFactory()
.getMappingMetamodel()
.getEntityDescriptor(Car.class)
.getPropertyType("types");
List<Car> list = session.createQuery(
"SELECT * FROM cars c WHERE (:carTypes) IN (c.types)",
Car.class
)
.setParameter("carTypes", carTypes, type)
.getResultList();

ERROR: operator does not exist: timestamp without time zone >= boolean Hint: No operator matches the given name and argument type(s)

Am trying to execute a Named Query using JPA. Query has to search and pull the records based on criteria of the query. Criteria is query should pull the records between specific given times(Records between From and To Dates provided) and name of the Application.
Query works fine, when executed in Postgresql. But, through JPA it gives error while executing the query
Here is my Query in PostgreSQL :
SELECT auditLog.busn_sys_id
, sourceSystem.busn_sys_full_nm
, auditLog.purge_ts
, auditLog.rec_purge_cnt
FROM rec_ret.rec_rtn_purge_adt auditLog
LEFT JOIN gbl_dm.gbl_busn_sys_dm sourceSystem on (auditLog.busn_sys_id = sourceSystem.busn_sys_id)
WHERE (auditLog.purge_ts BETWEEN '2019-08-19' AND '2019-08-25')
and sourceSystem.busn_sys_full_nm like 'PROFILE'
order by auditLog.busn_sys_id ;
Here is my JPA implementation to get Results List
try{
Query query = entityManager.createNativeQuery("SELECT auditLog.busn_sys_id, sourceSystem.busn_sys_full_nm, auditLog.purge_ts, auditLog.rec_purge_cnt " +
"FROM rec_ret.rec_rtn_purge_adt auditLog " +
"LEFT JOIN gbl_dm.gbl_busn_sys_dm sourceSystem on (auditLog.busn_sys_id = sourceSystem.busn_sys_id) " +
"WHERE (auditLog.purge_ts BETWEEN auditLog.purge_ts = :requestedFrom AND auditLog.purge_ts = :requestedTo) " +
//"WHERE (auditLog.purge_ts BETWEEN requestedFrom = (?) AND requestedTo = (?)) " +
"and sourceSystem.busn_sys_full_nm = :sourceSystem " +
"order by auditLog.busn_sys_id ");
query.setParameter("requestedFrom",auditLogCriteria.getFromDate());
query.setParameter("requestedTo",auditLogCriteria.getToDate());
query.setParameter("sourceSystem",auditLogCriteria.getSourceSystem());;
query.executeUpdate();
return query.getResultList();
}catch (Exception e){
logger.error("Fetching of logs failed with message : " + e.getMessage());
throw e;
}
Here is my implementation of Entity/Model class code
#NotNull (message = "Name of the Source System should be entered")
private String sourceSystem;
#NotNull (message = "Specify FromDate to filter records")
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss[.SSS]")
#Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime fromDate;
#NotNull (message = "Specify ToDate to filter records")
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss[.SSS]")
#Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime toDate;
\\ Getters and Setters
Here is the Error :
Hibernate: SELECT auditLog.busn_sys_id, sourceSystem.busn_sys_full_nm, auditLog.purge_ts, auditLog.rec_purge_cnt FROM rec_ret.rec_rtn_purge_adt auditLog LEFT JOIN gbl_dm.gbl_busn_sys_dm sourceSystem on (auditLog.busn_sys_id = sourceSystem.busn_sys_id) WHERE (auditLog.purge_ts BETWEEN auditLog.purge_ts = ? AND auditLog.purge_ts = ?) and sourceSystem.busn_sys_full_nm = ? order by auditLog.busn_sys_id
[ERROR] 2019-08-29 10:02:00.558 [http-nio-8080-exec-2] SqlExceptionHelper - ERROR: operator does not exist: timestamp without time zone >= boolean
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Position: 267
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1593)
So, result should be all the records matching with the criteria has to be returned as a response to JSON request
This part of your JPA query looks wrong:
BETWEEN auditLog.purge_ts = :requestedFrom AND auditLog.purge_ts = :requestedTo
I think it should be:
BETWEEN :requestedFrom AND :requestedTo

How to use mongodb query in hibernate OGM?

I want to find only the username field in my Registration collection
I am using the following query
db.Registration.find( {"username":"abcd"}, {username:1, _id:0} )
How will I write this query in hibernate?
If your entity looks like this:
#Entity
class Registration {
#Id
String id;
String username:
}
This should work:
String query = "FROM Registration r WHERE r.username = :username ORDER by r.username ASC, r.id DESC"
List<Registration> results = entityManager.createQuery( query )
.setParameter("username", "abcd")
.getResultList()
or
Registration results = entityManager.createQuery( query )
.setParameter("username", "abcd")
.getSingleResult()
You can also use native queries but I will let you to the documentation: https://docs.jboss.org/hibernate/ogm/5.4/reference/en-US/html_single/#ogm-mongodb-queries-native
You'll need to annotate the (none PK) columns you want to retrieve in the Entity with:
#Column(name = "username")

QueryDSL and SQL Function from Postgres

I would like to use Postgres FullText search with QueryDsl JPA.
Generated in SQL:
select *
from film
where to_tsquery ('tarzan') ## to_tsvector('french',film.title) = true
to get all film containing tarzan in their title.
In JPA I define a custom function 'ftsMatch' which I could use like that:
String jpql = "select film from Film film where ftsMatch(:queryString, film.titre) = true";
I QueryDSL I would like to have an opportunity to define a predicate on String type :
QFilm.film.titre.ftsMatch('tarzan')
I haven't found any solution
What I would like to do is to extends the com.querydsl.core.types.dsl.StringExpression.class
and add a custom function fullTextMatch() which could be used like :
BooleanBuilder booleanBuilder = new BooleanBuilder(QFilm.film.titre.fullTextMatch(_titre, "french"));
it would turn into SQL :
select film0_.id as id1_2_ .. from film film0_
where to_tsquery (?) ## to_tsvector('pg_catalog.french',film0_.titre)=true
I haven't found how to get the QueryDSL syntax above, but found the following solution:
1/ define Custom Dialect for Postgres
and register the Customm function on this dialect :
public class CustomFullTextPostgresDialect extends PostgreSQL94Dialect {
public CustomFullTextPostgresDialect() {
registerFunction("ftsMatch", new PostgreSQLFullTextSearchFunction());
}
}
2/ Code the custom function PostgreSQLFullTextSearchFunction implementing org.hibernate.dialect.function.SQLFunction
This function 'ftsMacth' will generate the SQL :
String fragment = " to_tsquery (" + value + ") ## to_tsvector(" + ftsConfig + "," + field + ")";
This step give me access to Posgres FullText in JPA :
String jpql = "select film from Film film "
+ "where FUNCTION( 'ftsMatch', :titre,'pg_catalog.french', film.titre) = true";
TypedQuery<Film> typedQuery = em.createQuery(jpql, Film.class);
typedQuery.setParameter("titre", _titre);
List<Film> list = typedQuery.getResultList();
3/Use QueryDsl to relay to the custom function defined on the extended postgres Dialect :
BooleanTemplate predicate = Expressions
.booleanTemplate("FUNCTION('ftsMatch', {0},'pg_catalog.french', film.titre) = true ", _titre);
Page<Film> page = filmRepository.findAll(predicate, _pageable);
But with this QueryDSL solution, I still need the Hibernate customization. And the syntax is no longer DSL oriented