Postgresql Search for a value in jsonb object - postgresql

I have a jsonb field in a table having values of the form
{
"message": {
"sender": {
"from": "91**********"
},
"channel": "some kind of text",
"content": {
"text": "some kind of text",
"type": "text"
},
"recipient": {
"to": "91**********",
"recipient_type": "some kind of text"
},
"preferences": {
"webHookDNId": "some kind of text"
}
},
"metaData": {
"version": "some kind of text"
}
}
Now i want to search for all such value which in "to" key of the object has a certain phone number. i am using following query for this but it is not working
select * from table_name where (column1::jsonb ? '91**********') ;

? looks for a top-level key. The JSON you show only has two top-level keys, "message" and "metadata". So of course they don't match to '91**********'.
You probably want the containment operator #>:
#> '{"message":{"recipient":{"to":"91**********"}}}'
This will be supported by the either type of JSONB GIN index on your column.

You can use the -> and ->> operators to extract the value from a key:
select *
from the_table
where (the_column -> 'recipient' ->> 'to') = '91**********';
Or the #>> operator
select *
from the_table
where the_column #>> '{recipient,to}' = '91**********';

Related

Update property of object in jsonb array and keep other properties

I have a postgres table with a jsonb colum like this:
create table if not exists doc
(
id uuid not null
constraint pkey_doc_id
primary key,
data jsonb not null
);
INSERT INTO doc (id, data) VALUES ('3cf40366-ea58-402d-b63b-c9d6fdf99ec8', '{"Id": "3cf40366-ea58-402d-b63b-c9d6fdf99ec8", "Tags": [{"Key": "inoivce", "Value": "70086"},{"Key": "customer", "Value": "100233"}] }' );
INSERT INTO doc (id, data) VALUES ('ae2d1119-adb9-41d2-96e9-53445eaf97ab', '{"Id": "ae2d1119-adb9-41d2-96e9-53445eaf97ab", "Tags": [{"Key": "project", "Value": "12345"},{"Key": "customer", "Value": "100233"}]}' );b9-41d2-96e9-53445eaf97ab", "Tags": [{"Key": "customer", "Value": "100233"}]}' )
Tags.Key in the first row contains a typo inoivce which I want to fix to invoice:
{
"Id": "3cf40366-ea58-402d-b63b-c9d6fdf99ec8",
"Tags": [{
"Key": "inoivce",
"Value": "70086"
},{
"Key": "customer",
"Value": "100233"
}]
}
I tried this:
update doc set data = jsonb_set(
data,
'{"Tags"}',
$${"Key":"invoice"}$$
) where data #> '{"Tags": [{ "Key":"inoivce"}]}';
The typo gets fixed but I'm loosing the other Tags elements in the array:
{
"Id": "3cf40366-ea58-402d-b63b-c9d6fdf99ec8",
"Tags": [{"Key": "invoice"}]
}
How can I fix the typo without removing the other elements of the Tags array?
Dbfiddle for repro.
One possible solution, not so obvious : we need a CTE because the idea here is to loop on the 'Tags' jsonb array elements using the jsonb_agg aggregate function to rebuild the array, but the SET clause of an UPDATE doesn't accept aggregate functions ...
WITH list AS
( SELECT d.id, (d.data - 'Tags') || jsonb_build_object('Tags', jsonb_agg(jsonb_set(e.content, '{Key}' :: text[], to_jsonb(replace(e.content->>'Key', 'inoivce', 'invoice'))) ORDER BY e.id)) AS data
FROM doc AS d
CROSS JOIN LATERAL jsonb_array_elements(d.data->'Tags') WITH ORDINALITY AS e(content, id)
WHERE d.data #? '$.Tags[*] ? (exists(# ? (#.Key == "inoivce")))'
GROUP BY d.id, d.data
)
UPDATE doc AS d
SET data = l.data
FROM list AS l
WHERE d.id = l.id
see the result in dbfiddle

Using SQLAlchey query top x items in a Postgres JSONB field

I have a model with a JSONB field (Postgres).
from sqlalchemy.dialects.postgresql import JSONB
class Foo(Base):
__tablename__ = 'foo'
data = Column(JSONB, nullable=False)
...
where the data field looks like this:
[
{
"name": "a",
"value": 0.0143
},
{
"name": "b",
"value": 0.0039
},
{
"name": "c",
"value": 0.1537
},
...
]
and, given a search_name I want to return the rows where name is in the top x ranked names.
I know I can access the fields with something like:
res = session.query(Foo).filter(Foo.data['name'] == search_name)
but how do I order the JSON and extract the top names from that?
A SQLAlchemy solution would be preferred, but also a plain SQL one I can use as raw is fine.

JSONB Represent jsonb key value like array

I have field extra with type jsonb in my table product. And I need get uniq key with uniq values for each key from all products row. Example data in extra field
{"SIZE": "110/116", "COLOUR": "Vit", "GENDER": "female", "AGE_GROUP": "Kids", "ALTERNATIVE_IMAGE": "some_path"}
for now I use query like this
select DISTINCT e.key, array_agg(DISTINCT e.value) as fields
from products AS p
join jsonb_each_text(p.extras) e on true
GROUP BY e.key
Ad have respnse (small part with some keys in full response all keys are present) like this
[
{
"key": "AGE_GROUP",
"fields": "{Adult,children,Kids}"
},
{
"key": "GENDER",
"fields": "{female,male,man}"
}
]
how to change it to array for fields alias ?
like this
[
{
"AGE_GROUP": ["Adult","children","Kids"]
},
{
"GENDER": ["female","male","man"]
}
]
or maybe whould be great like this
[
"some_alias": [{"AGE_GROUP": "Adult", "AGE_GROUP": "children", "AGE_GROUP": "Kids"}],
"some_alias": [{"GENDER": "female", "GENDER": "male", "GENDER": "man"}]
]
This will get you the former form I think:
select jsonb_agg(jsonb_build_object(k,v)) from (
select DISTINCT e.key, jsonb_agg(DISTINCT e.value) as fields
from products AS p
join jsonb_each_text(p.extras) e on true
GROUP BY e.key
) b(k,v);
Best regards,
Bjarni

Query in JSONB array of Postgres database

Below JSON is one of the column of type JSONB in my table 'logic', I want to query to check how many rows are there with type: QUESTION (any entry within conditions).
{
"name": null,
"conditions": [
{
"type": "QUESTION",
"question": {
}
},
{
"type": "QUESTION",
"question": {
}
},
{
"type": "FIELD",
"question": {
}
}
],
"expression": "A"
}
If you want to check the number of times "type": "QUESTION" entry appears within conditions of the jsonb column throughout the table.
select count(*) FROM logic CROSS JOIN LATERAL
jsonb_array_elements(jsonb_col->'conditions')as j(typ)
WHERE j->>'type' = 'QUESTION'
If you want to check the number of times "type": "QUESTION" entry appears within conditions for each row.
select jsonb_col,count(*) FROM logic CROSS JOIN LATERAL
jsonb_array_elements(jsonb_col->'conditions')as j(typ)
WHERE j->>'type' = 'QUESTION'
group by jsonb_col
If you want to check how many rows have at least one entry within conditions with
'type' = 'QUESTION',
select count(*) FROM
(
select DISTINCT jsonb_col FROM logic CROSS JOIN LATERAL
jsonb_array_elements(jsonb_col->'conditions')as j(typ)
WHERE j->>'type' = 'QUESTION'
)s;
Use the query which you find is appropriate for you
Demo

Postgres: Delete object from anonymous jsonb array element

I have a table with 2 fields:
table documents
docu_id uuid
attachments jsonb
A sample data for the attachments jsonb column would be:
[
{
"size": 10,
"attach_id": "d3a21f904068"
},{
"Size": 0.143,
"attach_id": "5ba4b285565b"
}
]
I have seen many examples of how to update/delete a jsonb based on field name, but is it possible to delete an anonymous object from an anonymous array where "attach_id" = "X" and "docu_id"="Y":
delete from documents
where docu_id = "Y"
and
where attachments #> '[{"attach_id": "X"}]'
Ok found the solution so I'm sharing it here, (rextester link http://rextester.com/YICZ86369):
Inserting the data
create table documents(docu_id text, attachments jsonb);
insert into documents values
('001',
'[
{
"name": "uno",
"id":"1"
},
{
"name": "dos",
"id":"2"
},
{
"name": "tres",
"id":"3"
}
]'
),
('002',
'[
{
"name": "eins",
"id":"1"
},
{
"name": "zwei",
"id":"2"
}
]'
);
select * from documents;
The solution
UPDATE documents
SET attachments = attachments #-
array(
SELECT i
FROM generate_series(0, jsonb_array_length(attachments) - 1) AS i
WHERE (attachments->i->'id' = '"2"')
)::text[] /* cast as text */
where docu_id = '002';
select * from documents;