Querying jsonb column containing a json array with a single element - postgresql

I want to be able to use the same query syntax to return both rows
Given a jsonb column, named 'tags' in a table called 'qux' with sample data in row 1:
{
"foo": ["1","2"]
}
and row 2:
{
"foo": ["3"]
}
and the pre-requisite index created on the column 'tags':
CREATE INDEX tag_idx ON tags USING GIN (tags);
When I run the following query:
SELECT count(*) FROM "qux" WHERE tags #> '{"foo": ["1"]}'
I expect to get a row back, which is correct.
If I run:
SELECT count(*) FROM "qux" WHERE tags #> '{"foo": ["3"]}'
I do not get any rows back, which feels unexpected. I can get the row back if I remove the square brackets on the second example, however that syntax breaks the first example.
Is this a known bug, or a problem with indexing? The version of postgres is 9.5

Related

Search for string in jsonb values - PostgreSQL

For simplicity, a row of table looks like this:
key: "z06khw1bwi886r18k1m7d66bi67yqlns",
reference_keys: {
"KEY": "1x6t4y",
"CODE": "IT137-521e9204-ABC-TESTE"
"NAME": "A"
},
I have a jsonb object like this one {"KEY": "1x6t4y", "CODE": "IT137-521e9204-ABC-TESTE", "NAME": "A"} and I want to search for a query in the values of any key. If my query is something like '521e9204' I want it to return the row that reference_keys has '521e9204' in any value. Basicly the keys don't matter for this scenario.
Note: The column reference_keys and so the jsonb object, are always a 1 dimensional array.
I have tried a query like this:
SELECT * FROM table
LEFT JOIN jsonb_each_text(table.reference_keys) AS j(k, value) ON true
WHERE j.value LIKE '%521e9204%'
The problem is that it duplicates rows, for every key in the json and it messes up the returned items.
I have also thinked of doing something like this:
SELECT DISTINCT jsonb_object_keys(reference_keys) from table;
and then use a query like:
SELECT * FROM table
WHERE reference_keys->>'CODE' like '%521e9204%'
It seems like this would work but I really don't want to rely on this solution.
You can rewrite your JOIN to an EXISTS condition to avoid the duplicates:
SELECT t.*
FROM the_table t
WHERE EXISTS (select *
from jsonb_each_text(t.reference_keys) AS j(k, value)
WHERE j.value LIKE '%521e9204%');
If you are using Postgres 12 or later, you can also use a JSON path query:
where jsonb_path_exists(reference_keys, 'strict $.** ? (# like_regex "521e9204")')

postgres remove specific element from jsonb array

I am using postgres 10
I have a JsonArray in a jsonb column named boards.
I have a GIN index on the jsonb column.
The column values look like this:
[{"id": "7beacefa-9ac8-4fc6-9ee6-8ff6ab1a097f"},
{"id": "1bc91c1c-b023-4338-bc68-026d86b0a140"}]
I want to delete in all the rows in the column the element
{"id": "7beacefa-9ac8-4fc6-9ee6-8ff6ab1a097f"} if such exists(update the column).
I saw that it is possible to delete an element by position with operator #- (e.g. #-'{1}') and I know you can get the position of an element using "with ordinality" but i cant manage to combine the two things.
How can i update the jsonarray?
One option would be using an update statement containing a query selecting all the sub-elements except {"id": "7beacefa-9ac8-4fc6-9ee6-8ff6ab1a097f"} by using an inequality, and then applying jsonb_agg() function to aggregate those sub-elements :
UPDATE user_boards
SET boards = (SELECT jsonb_agg(j.elm)
FROM user_boards u
CROSS JOIN jsonb_array_elements(boards) j(elm)
WHERE j.elm->>'id' != '7beacefa-9ac8-4fc6-9ee6-8ff6ab1a097f'
AND u.ID = user_boards.ID
GROUP BY ID)
where ID is an assumed identity(unique) column of the table.
Demo

Querying Postgres SQL JSON Column

I have a json column (json_col) in a postgres database with the following structure:
{
"event1":{
"START_DATE":"6/18/2011",
"END_DATE":"7/23/2011",
"event_type":"active with prior experience"
},
"event2":{
"START_DATE":"8/20/11",
"END_DATE":"2/11/2012",
"event_type":"active"
}
}
[example of table structure][1]
How can I make a select statement in postgres to return the start_date and end_date with a where statement where "event_type" like "active"?
Attempted Query:
select person_id, json_col#>>'START_DATE' as event_start, json_col#>>'END_DATE' as event_end
from data
where json_col->>'event_type' like '%active%';
Returns empty columns.
Expected Response:
event_start
6/18/2011
8/20/2011
It sounds like you want to unnest your json structure, ignoring the top level keys and just getting the top level values. You can do this with jsonb_each, looking at resulting column named 'value'. You would put the function call in the FROM list as a lateral join (but since it is a function call, you don't need to specify the LATERAL keyword, it is implicit)
select value->>'START_DATE' from data, jsonb_each(json_col)
where value->>'event_type' like '%active%';

How to filter data from postgresql which has jsonb nested field in the array field of jsonb?

i have a table with a jsonb column and documents are like these(simplified)
{
"a": 1,
"rg": [
{
"rti": 2
}
]
}
I want to filter all the rows which has 'rg' field and there is at least one 'rti'field in the array.
My current solution is
log->>'rg' ilike '%rti%'
Is there another approach, probably a faster solution exists.
Another approach would be applying jsonb_each to the jsonb object and then jsonb_array_elements_text to the extracted value from jsonb_each method :
select id, js_value2
from
(
select (js).value as js_value, jsonb_array_elements_text((js).value) as js_value2,id
from
(
select jsonb_each(log) as js, id
from tab
) q
where (js).key = 'rg'
) q2
where js_value2 like '%rti%';
Demo

get first element from jsonb list of strings postgres

I have a List which is stored in my table as a jsonb and need a native query to get the first element from this jsonb column
Tried using jsonb_array_elements_text but couldn't get it to work.
select col from tbl;
returns:
["abc", "def", "etc"]
I need a query which can just return me abc
You can use the operator that picks the n-th element of an array:
select col ->> 0 as first_element
from tbl;
Note that unlike Postgres native arrays, the first element in a JSON array has the index 0