Trying to query product_id and inner JSONB value "quantity_on_hand" with "unit:one". Below is example table
Products table
| product_id | data |
| -------- | -------------|
| 00445 | {"storage"...}| - rest of data specified right below
{
"storage": [
{
"unit": "one",
"quantity": 3,
},
{
"unit": "two",
"quantity": 2,
}
}
I found a query:
SELECT product_id, e -> 'quantity' as quant
FROM Products t,
jsonb_array_elements(t.value->'storage') e
WHERE (product_id) IN (('00445'));
The query returns following output:
product_id | quant
00445 | 3
00445 | 2
Please advise how to set rule: "quantity_on_hand" with "unit:one" to return only:
product_id | quant
00445 | 3
Thanks
You can add a clause for filtering the result of the jsonb_array_elements to only include elements where the JSON key "unit"'s value is "one":
SELECT product_id,
e -> 'quantity' AS quant
FROM Products t,
JSONB_ARRAY_ELEMENTS(t.value -> 'storage') e
WHERE (product_id) IN (('00445'))
AND e ->> 'unit' = 'one';
This should give:
product_id | quant
------------+-------
1 | 3
(1 row)
See https://www.postgresql.org/docs/14/functions-json.html for more information on JSONB operators and functions in Postgres.
I am selecting rows as
`SELECT
jsonb_build_object('platform_id',pl.id,'platform_Name',pl."name") as "platform" from
"platforms" as pl ON pl.id = up."platform_id"
WHERE usrs.id = ${userid}`
I am getting result as JSON
"platform": {
"platform_id": 5,
"platform_Name": "Snapchat"
}
but I want the platform result as "array of object " like below
DESIRED RESULT :
"platform": [{
"platform_id": 5,
"platform_Name": "Snapchat"
}]
How to make write query to get it as array ?
I recreated a similar example with:
create table platforms (id int, name text, user_id int);
insert into platforms values (1, 'snapchat',100),(2, 'fb', 100),(3, 'instagram', 200), (4, 'twitter',100);
The platforms table contains:
id | name | user_id
----+-----------+---------
1 | snapchat | 100
2 | fb | 100
3 | instagram | 200
4 | twitter | 100
(4 rows)
You can solve the problem in 2 steps:
create the json object with id and name using jsonb_build_object
aggregate over user_id using jsonb_agg
the query is
with create_doc as (
SELECT
user_id,
jsonb_build_object('platform_id',id,'platform_Name',name) as platform
from platforms
)
select user_id, jsonb_agg(platform) from create_doc group by user_id;
result
user_id | json_agg
---------+----------------------------------------------------------------------------------------------------------------------------------------------
200 | [{"platform_id": 3, "platform_Name": "instagram"}]
100 | [{"platform_id": 1, "platform_Name": "snapchat"}, {"platform_id": 2, "platform_Name": "fb"}, {"platform_id": 4, "platform_Name": "twitter"}]
(2 rows)
I have a table with jsonb column datatype
+-----+--------------------------------------------------------------------------------+
| id | value |
+-----+--------------------------------------------------------------------------------+
| 1 | {"t1": "val", "value": [{"id": "1", "name": "abc"},{"id": "2", "name": "xyz"}] |
| 2 | {"t1": "val", "value": [{"id": "2", "name": "xyz"},{"id": "3", "name": "pqr"}] |
+-----+--------------------------------------------------------------------------------*
SELECT 'True' as status
FROM table t
where t.value->'value'->-1 -> 'id' IN ('"2"','"1"')
I want to fetch Ture or false along with each id checked in where clause.
Kindly help me in this query
You need to move the condition into the SELECT list, but you have to iterate over all array elements:
select t.id,
exists(select *
from jsonb_array_elements(t.value -> 'value') as v(item)
where item ->> 'id' in ('1','2')) as status
from the_table t;
With Postgres 12 or later, you can extract all IDs into an array and then use the ?| operator:
select t.id,
jsonb_path_query_array(t.value -> 'value', '$[*].id') ?| array['1','2'] as status
from the_table t;
I have a jsonb column with this format.
{
"categoryList": [{
"category_menu_id": "51",
"is_featured_product": 0
}, {
"category_menu_id": "54",
"is_featured_product": 1
}]
}
How to remove category by category_menu_id?
This select query is working fine by category_menu_id.
select product_category
from product
where product_category->'categoryList' #> '[{"category_menu_id": "51"}]';
Example data (note that I have added a primary key id to enable updating the table):
create table product(id int primary key, product_category jsonb);
insert into product values
(1,
'{
"categoryList": [{
"category_menu_id": "51",
"is_featured_product": 0
}, {
"category_menu_id": "54",
"is_featured_product": 1
}]
}');
This query skips the element with "category_menu_id": "51" from the json array:
select jsonb_build_object('categoryList', jsonb_agg(value))
from product,
jsonb_array_elements(product_category->'categoryList')
where value->>'category_menu_id' <> '51';
jsonb_build_object
--------------------------------------------------------------------------
{"categoryList": [{"category_menu_id": "54", "is_featured_product": 1}]}
(1 row)
Use the above query to update the table:
update product p
set product_category = (
select jsonb_build_object('categoryList', jsonb_agg(value))
from product ps,
jsonb_array_elements(product_category->'categoryList')
where ps.id = p.id -- important! primary key to identify a row
and value->>'category_menu_id' <> '51')
returning *;
id | product_category
----+--------------------------------------------------------------------------
1 | {"categoryList": [{"category_menu_id": "54", "is_featured_product": 1}]}
(1 row)
I have asked way too many questions on jsonb and still feel a bit lost.
I have the following tables:
CREATE TABLE _data (
id serial PRIMARY KEY
, data jsonb
);
--with the following rows:
pk | data
---|------------------------
1 | {"year": 2012, "model": "honda"}
2 | {"year": 2014, "model": "toyota"}
CREATE TABLE _people (
pk serial PRIMARY KEY
user integer
, data integer
, updated timestamp without time zone
, documents jsonb
);
-- with the following rows:
pk | user | data| updated | documents
----|--------|-----|--------------------------|---------------
1 | 1 | 1 | 2015-08-22 16:05:40.76 | [{"type": "spreadsheet", "title": "mySpreadsheet", "length": 1278, "ignoredKey": "ignoreme"}, {"type": "document", "title": "My Nice Title"}]
2 | 1 | 1 | 2015-08-24 16:03:00 | [{"type": "spreadsheet", "title": "anothersheet", "length": 1400, "ignoredKey": "ignoreme"}, {"type": "document", "title": "here's another document"}]
CREATE TABLE _users (
pk serial PRIMARY KEY
, name text
);
-- with the following example row:
pk | name
-----|------
1 | Jim Bob
I am trying to get the following output (notice I am ignoring some keys in my documents...specifically "ignoredKey":
User | Data | Updated |Documents
---------|----------------------------------|---------------------------|------------
Jim Bob | {"year": 2012, "model": "honda"} |2015-08-22 16:05:40.764122 | [{"type": "spreadsheet", "title": "mySpreadsheet", "length": 1278}, {"type": "document", "title": "My Nice Title"}]
Jim Bob | {"year": 2014, "model": "toyota"} |2015-08-24 16:03:00 | [{"type": "spreadsheet", "title": "anothersheet", "length": 1400}, {"type": "document", "title": "here's another document"}]
I have:
SELECT p.pk, u.name, custom_docs, d.data FROM _people p,
jsonb_to_recordset(p.documents) doc(type text, title text, length numeric)
LEFT JOIN _data d ON p.data = d.pk
LEFT JOIN _users u ON p.user = u.pk
Which gives me the error:
ERROR: invalid reference to FROM-clause entry for table "p"
LINE 3: LEFT JOIN _data d ON p.data = d.pk
^
HINT: There is an entry for table "p", but it cannot be referenced from this part of the query.
EDIT #1:
As pointed below I need the "Documents" column that is created to be an array of objects...in the form of:
[{"type": "spreadsheet", "title": "mySpreadsheet", "length": 1278}, {"type": "document", "title": "My Nice Title"}]
Any other format is hard to use once it is retrieved.
EDIT #2:
Dmitry's answer helped get me further along but the "Documents" column contains ALL of the documents from all rows rather than those I need:
WITH docs AS (
SELECT array_agg(to_json(changed_structure)) as changed_json_array
FROM _people p,jsonb_to_recordset(p.documents) AS changed_structure(type text, title text, length numeric)
)
SELECT u.name,d.data,p.updated,docs.changed_json_array FROM docs,_people p
LEFT JOIN _users u ON u.pk = p.user
LEFT JOIN _data d ON d.pk = p.data;
This gives me:
name | data | updated | documents
------- | ----------------------------------| ---------------------------|
Jim Bob | {"year": 2012, "model": "honda"} | 2015-08-22 16:05:40.764122 | {"{\"type\":\"spreadsheet\",\"title\":\"mySpreadsheet\",\"length\":1278}","{\"type\":\"document\",\"title\":\"My Nice Title\",\"length\":null}","{\"type\":\"spreadsheet\",\"title\":\"anothersheet\",\"length\":1400}","{\"type\":\"document\",\"title\":\"here's another document\",\"length\":null}"}
Jim Bob | {"year": 2014, "model": "toyota"} | 2015-08-24-16:03:00 | {"{\"type\":\"spreadsheet\",\"title\":\"mySpreadsheet\",\"length\":1278}","{\"type\":\"document\",\"title\":\"My Nice Title\",\"length\":null}","{\"type\":\"spreadsheet\",\"title\":\"anothersheet\",\"length\":1400}","{\"type\":\"document\",\"title\":\"here's another document\",\"length\":null}"}
The key motive here is to use json_agg(to_json(doc)) from jsonb_to_recordset(p.documents):
select pk, json_agg(to_json(doc)) doc
from _people p, jsonb_to_recordset(p.documents) doc(type text, title text, length numeric)
group by 1
pk | doc
----+-----------------------------------------------------------------------------------------------------------------------------------
1 | [{"type":"spreadsheet","title":"mySpreadsheet","length":1278}, {"type":"document","title":"My Nice Title","length":null}]
2 | [{"type":"spreadsheet","title":"anothersheet","length":1400}, {"type":"document","title":"heres another document","length":null}]
(2 rows)
and appropriate use of the join:
select u.name, d.data, p.updated, s.doc
from _people p
left join _users u on u.pk = p.auser
left join _data d on d.pk = p.data
left join (
select pk, json_agg(to_json(doc)) doc
from _people p, jsonb_to_recordset(p.documents) doc(type text, title text, length numeric)
group by 1
) s on s.pk = p.pk
name | data | updated | doc
---------+----------------------------------+------------------------+-----------------------------------------------------------------------------------------------------------------------------------
Jim Bob | {"year": 2012, "model": "honda"} | 2015-08-22 16:05:40.76 | [{"type":"spreadsheet","title":"mySpreadsheet","length":1278}, {"type":"document","title":"My Nice Title","length":null}]
Jim Bob | {"year": 2012, "model": "honda"} | 2015-08-24 16:03:00 | [{"type":"spreadsheet","title":"anothersheet","length":1400}, {"type":"document","title":"heres another document","length":null}]
(2 rows)
Note: I had to change _users.user to _users.auser.
[changed]
WITH docs AS (
SELECT array_agg(to_json(changed_structure)) as changed_json_array
FROM _people p,jsonb_to_recordset(p.documents) AS changed_structure(type text, title text, length numeric)
)
SELECT u.name,d.data,p.updated,docs.changed_json_array FROM docs,_people p
LEFT JOIN _users u ON u.pk = p.user
LEFT JOIN _data d ON d.id = p.data;