I have a column called tags
of type JSONB
in my PostgreSQL table called EMPLOYEE
.
There is a use case where I want to allow users to query this JSONB column, i.e., tags
.
Users can give inputs like:
- tags.inoffice.present = 5
- tags.inoffice = 5
These inputs are then converted to the following queries in my python application:
SELECT *
FROM EMPLOYEE
WHERE CAST((((EMPLOYEE.tags -> 'inoffice')) ->> 'present') AS FLOAT) = 5.0;
and
SELECT *
FROM EMPLOYEE
WHERE CAST((((EMPLOYEE.tags)) ->> 'inoffice') AS FLOAT) = 5.0;
The first query returns the correct output as expected. However, the second query fails because it cannot cast into a float, resulting in the following error:
psql:commands.sql:29: ERROR: invalid input syntax for type double precision: "{"present": 5}"
The tags
column is a free field, and the table can contain any JSON structure. Therefore, there are no predefined valid/invalid key-value pairs in that column.
What is the best way to prevent this problem?
Solutions that I have considered:
- Using a
try except
block in the Python application to catch errors. If an error is raised, check if the given path can be cast to float and if not, raise aValueError
. However, I am unsure how to check if the given input path can be converted to float or not.
Is there any other better way to handle this situation?
Here is a sample playground for the above-mentioned issue.
-- create
CREATE TABLE EMPLOYEE (
empId INTEGER PRIMARY KEY,
name TEXT NOT NULL,
tags JSONB
);
-- insert
INSERT INTO EMPLOYEE (empId, name, tags)
VALUES
(1, 'John Doe', '{"inoffice": {"present": 5}}'),
(2, 'Jane Smith', '{"inoffice": {"present": 15}}'),
(3, 'Bob Johnson', '{"inoffice": {"present": 20}}'),
(4, 'Alice Brown', '{"inoffice": {"present": 4}}');
-- fetch
SELECT *
FROM EMPLOYEE
WHERE CAST((((EMPLOYEE.tags -> 'inoffice')) ->> 'present') AS FLOAT) < 12.0;
SELECT *
FROM EMPLOYEE
WHERE CAST((((EMPLOYEE.tags)) ->> 'inoffice') AS FLOAT) < 12.0;
2
Answers
The
@?
and@@
operators take a path query and silently ignore errors. (The former is for SQL-standard JSON path queries, the latter for Postgres-specific boolean predicates.)You can also do this with
jsonb_path_exists
if you pass thesilent
parameter astrue
. You can also use injected parameters using this method with thevars
parameter.See also the docs.
If I got it right, you want to be able to check if a specific path could be converted to float or not. It is possible using Case expression + regex to do the test and then you could decide what to do.
Bellow is such a test for paths from your queries using regex to check if there are only numbers in text from start to end….