Query in json in postgres with multiple values - json

I have json stored [1,2,4,5].I have array s like [1,23,4]. I want to check either value of s array exist in json fields. Other options I may need to store array like ['1','2','4','5'] so i can use?| operator or their is anything else i can do ?

There is no ready-to-use function or operator to accomplish that. You can use the function:
create or replace function jsonb_int_array(jsonb)
returns integer[] language sql immutable as $function$
select array(select jsonb_array_elements_text($1)::int)
$function$;
In the query use the overlap operator:
with my_table(data) as (
values ('[1,2,4,5]'::jsonb)
)
select *
from my_table
where jsonb_int_array(data) && array[1,23,4]
data
--------------
[1, 2, 4, 5]
(1 row)

Related

Between clause on Array of numerical values in row for JSON type column

I have a table with single column containing JSON type objects (column type nvarchar) and have a requirement of filtering rows.
JSON object is an array of objects containing multiple fields, Is there a way I can apply between clause on each value of array and return that row if it matches.
ROW_1 = [{"key": 12}, {"key": 13}, {"key": 19}]
For the above string if between clause has range between 15 to 22, then this row should be selected.
There are two challenges I see in above requirement, 1 is to use wild_cards to select all keys and other to apply between clause on each value.
Similar use-case, is to select a row if it matches the value for which I did something like below
select *
from table
where CAST(JSON_QUERY(column, '$'), nvarchar(max)) LIKE '%"key": 12%'
Let me know if this can be done using a T-SQL query.
PS. Other alternatives include loading all data using python and filter there. (but my concern is that I would need to load complete data every time which might slowdown the filtering due to increase in number of rows in future).
You may use an APPLY operator and an OPENJSON() call to parse the stored JSON and apply the appropriate WHERE clause:
SELECT *
FROM (VALUES (N'[{"key": 12}, {"key": 13}, {"key": 19}]')) v (JsonData)
CROSS APPLY OPENJSON(v.JsonData) WITH ([key] int '$.key') j
WHERE j.[key] BETWEEN 5 AND 12

How can I pass array of tuples to sql statement using json

I’m trying to make the following sql statement in a json file:
SELECT user_id
FROM users_to_users
WHERE (user_id, contact_user_id, contact_blocked) IN ?
I tried providing an array of arrays for the ? Values but that returned an error. Is there a way with json to pass an array of tuples for the inserts in the above sql statement?
Simple Example:-
Use the FIND_IN_SET function:
SELECT t.*
FROM YOUR_TABLE t
WHERE FIND_IN_SET(3, t.ids) > 0
-- all books with tags starting 'Java':
SELECT * FROM `book`
WHERE JSON_SEARCH(tags, 'one', 'Java%') IS NOT NULL;
Check This Reference which uses JSON To see the whole possible Solutions
Reference Of FIND_IN_SET Answer

Querying a JSON array of objects in Postgres

I have a postgres db with a json data field.
The json I have is an array of objects:
[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]
I'm trying to return values for a specific key in a JSON array, so in the above example I'd like to return the values for name.
When I use the following query I just get a NULL value returned:
SELECT data->'name' AS name FROM json_test
Im assuming this is because it's an array of objects? Is it possible to directly address the name key?
Ultimately what I need to do is to return a count of every unique name, is this possible?
Thanks!
you have to unnest the array of json-objects first using the function (json_array_elements or jsonb_array_elements if you have jsonb data type), then you can access the values by specifying the key.
WITH json_test (col) AS (
values (json '[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]')
)
SELECT
y.x->'name' "name"
FROM json_test jt,
LATERAL (SELECT json_array_elements(jt.col) x) y
-- outputs:
name
--------------
"Mickey Mouse"
"Donald Duck"
To get a count of unique names, its a similar query to the above, except the count distinct aggregate function is applied to y.x->>name
WITH json_test (col) AS (
values (json '[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]')
)
SELECT
COUNT( DISTINCT y.x->>'name') distinct_names
FROM json_test jt,
LATERAL (SELECT json_array_elements(jt.col) x) y
It is necessary to use ->> instead of -> as the former (->>) casts the extracted value as text, which supports equality comparison (needed for distinct count), whereas the latter (->) extracts the value as json, which does not support equality comparison.
Alternatively, convert the json as jsonb and use jsonb_array_elements. JSONB supports the equality comparison, thus it is possible to use COUNT DISTINCT along with extraction via ->, i.e.
COUNT(DISTINCT (y.x::jsonb)->'name')
updated answer for postgresql versions 12+
It is now possible to extract / unnest specific keys from a list of objects using jsonb path queries, so long as the field queried is jsonb and not json.
example:
WITH json_test (col) AS (
values (jsonb '[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]')
)
SELECT jsonb_path_query(col, '$[*].name') "name"
FROM json_test
-- replaces this original snippet:
-- SELECT
-- y.x->'name' "name"
-- FROM json_test jt,
-- LATERAL (SELECT json_array_elements(jt.col) x) y
Do like this:
SELECT * FROM json_test WHERE (column_name #> '[{"name": "Mickey Mouse"}]');
You can use jsonb_array_elements (when using jsonb) or json_array_elements (when using json) to expand the array elements.
For example:
WITH sample_data_array(arr) AS (
VALUES ('[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]'::jsonb)
)
, sample_data_elements(elem) AS (
SELECT jsonb_array_elements(arr) FROM sample_data_array
)
SELECT elem->'name' AS extracted_name FROM sample_data_elements;
In this example, sample_data_elements is equivalent to a table with a single jsonb column called elem, with two rows (the two array elements in the initial data).
The result consists of two rows (one jsonb column, or of type text if you used ->>'name' instead):
extracted_name
----------------
"Mickey Mouse"
"Donald Duck"
(2 rows)
You should them be able to group and aggregate as usual to return the count of individual names.

WHERE clause for filtering by condition on any element of a JSONB array?

In PostgreSQL, using a JSONB column, I can store arrays of values. In a WHERE clause, I can then filter these arrays by performing comparisons on individual array items.
As an example, I can check "Is the first item of array data, cast to a number, greater than 5?" by using WHERE CAST((data -> 0) AS FLOAT) > 5.
What I would like to be able to do, is to check "Is any item of array data, cast to to a number, greater than 5?".
Is there a way to do this as part of an PostgreSQL query, as opposed to first fetching all data and then manually performing this filter?
Use the function jsonb_array_elements_text(), example:
with my_table (id, data) as (
values
(1, '[1,2,3]'::jsonb),
(2, '[4,5,6]'::jsonb)
)
select *
from my_table
where exists (
select
from jsonb_array_elements_text(data)
where value::float > 5
)
id | data
----+-----------
2 | [4, 5, 6]
(1 row)

Postgres 9.4 jsonb queries basic operators

Is there any way to make queries on a jsonb field in some table in Postgres that are basically equitable to the Mongodb query operators (listed here https://docs.mongodb.org/manual/reference/operator/query-comparison/)
I would like to be able to store some json objects in a postgres table for example:
{"power": 200},
{"power": 400},
{"power": 0},
{"power": 146297},
If I do the current method of
SELECT * FROM mytable where json_field ->> 'power' < '2';
I get retured both the row for power 0 and power 146297...
Is there some documentation somewhere that specifies how to do
gt, gte, lt, lte, eq, not equal, in array, not in array
You need to cast ->> string result values:
WITH mytable(json_field) AS ( VALUES
('{"power": 200}'::JSONB),
('{"power": 400}'::JSONB),
('{"power": 0}'::JSONB),
('{"power": 146297}'::JSONB)
)
SELECT * FROM mytable where (json_field->>'power')::INTEGER < 2;
Result is:
json_field
--------------
{"power": 0}
(1 row)
The documentation is on the postgresql page. The documentation states that the ->> operator returns string, your right hand operand is a string too so the result is correct.
To do what you wanted to do you must cast the result returned from the json to integer:
SELECT * FROM mytable where (json_field ->> 'power')::int < '2';
Please note the brackets are needed as not to case 'power' to int.