I'm using spring JPA with PostgreSQL database. I have an Entity as follow:
@Entity
@TypeDef(name="json_binary", typeClass = com.vladmihalcea.hibernate.type.json.JsonBinaryType.class)
public class LiveTokens {
@Id
@GeneratedValue()
private Long id;
private String username;
@Type(type="json_binary")
@Column(columnDefinition = "jsonb")
private Token token
}
and Token
:
public class Token {
private Long expireTime;
private String accessToken;
}
For saving object to column with Hibernate, I use Hibernate Types project.
Now I want to get All LiveToken
s that expired. I can't do it with Spring JPA. How do I query to posgresql jsonb column with Spring data JPA?
If you want to call a SQL function that processes the JSON column, then you just need to make sure you register the function with Hibernate prior to using it.
For JSON operators, like the PostgreSQL ones (e.g., ->>
), the only option you have is to use a native SQL query. JPQL or HQL don't support database-specific JSON operators.
Using EclipseLink and spring data jpa, if your data in db is something like: {"expireTime":102020230201, "accessToken":"SOMETHING" }, my first question is why to use long numbers for your dates instead of timestamps (ex '2019-09-14 12:05:00'). If you use timestamps there are also options to manage timezones (either from postgresql or from you source code).
Regarding your issue you may use the FUNC JPQL keyword of EclipseLink (Hibernate may have something similar) in order to run a database specific function. In the example below I use FUNC('jsonb_extract_path_text', lt.token, 'expireTime')
to get the values of the json for token.expireTime.
PostgreSql method jsonb_extract_path_text
returns text, thus you cannot do a less that condition, so I cast the output of the function using JPQL CAST keyword with (CAST -data- TO -type-)
.
@Repository
public interface MyRepository extends JpaRepository<LiveTokens, Integer> {
@Query(value = "SELECT lt FROM LiveTokens lt WHERE CAST(FUNC('jsonb_extract_path_text', lt.token, 'expireTime') AS LongType) < :expirirationThreshold")
List<LiveTokens> findByExpireTime(@Param("expirirationThreshold") Long expirirationThreshold);
}
Again, this is not tested.
This is how a native query using postgres JSON query operators would look like, incoorporating your example:
@Query(value="SELECT t.* FROM LiveTokens t WHERE CAST(t.token ->> 'expireTime' AS LONG) < now()", native=true)
Assuming your real tablename is LiveTokens, native queries do no longer use the JPA translations, and the tablename has to match the one in the DB. (You may also need to specify it's schema.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With