Adding more data in array of object in PostgreSQL - json

I have a table of cart with 2 columns (user_num, data).
user_num will have the phone number of user and
data will have an array of object like [{ "id": 1, "quantity": 1 }, { "id": 2, "quantity": 2 }, { "id": 3, "quantity": 3 }] here id is product id.
user_num | data
----------+--------------------------------------------------------------------------------------
1 | [{ "id": 1, "quantity": 1 }, { "id": 2, "quantity": 2 }, { "id": 3, "quantity": 3 }]
I want to add more data of products in above array of objects in PostgreSQL.
Thanks!

To add the value use the JSONB array append operator ||
Demo
update
test
set
data = data || '[{"id": 4, "quantity": 4}, {"id": 5, "quantity": 5}]'
where
user_num = 1;

Related

Select from mysql array of objects with integer number and value null or source to file without duplicates

Let's say I have a table with rows like number, image. But image is not mandatory, It can be null and when I'm selecting I want to prioritize the row with image over the one with null so i could get clean array with only one row per number.
SELECT DISTINCT number, image FROM table ORDER BY number ASC
What's now with SELECT DISTINCT:
[
{
"number": 1,
"image": null
},
{
"number": 1,
"image": "https://example.com/image1.png"
},
{
"number": 2,
"image": null
},
{
"number": 2,
"image": "https://example.com/image2.png"
},
{
"number": 3,
"image": "https://example.com/image3.png"
},
{
"number": 3,
"image": null
},
{
"number": 4,
"image": null
}
]
What I want to get:
[
{
"number": 1,
"image": "https://example.com/image1.png"
},
{
"number": 2,
"image": "https://example.com/image2.png"
},
{
"number": 3,
"image": "https://example.com/image3.png"
},
{
"number": 4,
"image": null
}
]
Try this:
SELECT number, image FROM table ORDER BY ISNULL(LEFT(image,0));

How to generate nested nth level JSON object in T-SQL?

I have below data
against below query
declare #t table
(
Id int identity,
name varchar(50),
rootid int,
level int
);
insert into #t(name, rootid, level)
values
('Home', 0, 0)
,('Transaction', 0, 0)
, ('Settings', 0, 0)
,('Purchase Request', 2, 1)
,('Purchase Order', 2, 1)
,('Inventory', 2, 1)
,('Payment Advice', 2, 1)
,('Setup', 3, 1)
,('Budget', 3, 1)
,('CRC', 3, 1)
,('Create PR', 4, 3);
select * from #t;
Desire output:
[{
"Id": 1,
"name": "Home",
"rootid": 0,
"level": 0
}, {
"Id": 2,
"name": "Transaction",
"rootid": 0,
"level": 0,
"children": [{
"Id": 4,
"name": "Purchase Request",
"rootid": 2,
"level": 1,
"children": [{
"Id": 11,
"name": "Create PR",
"rootid": 4,
"level": 3
}]
}, {
"Id": 5,
"name": "Purchase Order",
"rootid": 2,
"level": 1
}, {
"Id": 6,
"name": "Inventory",
"rootid": 2,
"level": 1
}, {
"Id": 7,
"name": "Payment Advice",
"rootid": 2,
"level": 1
}]
}, {
"Id": 3,
"name": "Settings",
"rootid": 0,
"level": 0,
"children": [{
"Id": 8,
"name": "Setup",
"rootid": 3,
"level": 1
}, {
"Id": 9,
"name": "Budget",
"rootid": 3,
"level": 1
}, {
"Id": 10,
"name": "CRC",
"rootid": 3,
"level": 1
}]
}]
Also Tried #Iptr answer:
;WITH result (id, name, rootId, parent, Level) AS
(
SELECT id,
name,
RootId,
Id as Parent,
0 as Level
FROM #t
WHERE RootId= 0
UNION ALL
SELECT t.id,
t.Name,
t.RootId,
r.Parent,
r.Level + 1
FROM #t t
INNER JOIN result r ON r.id = t.RootId
)
SELECT t.*, json_query(nullif(c.children, '[{}]')) as children
FROM #t as t
outer apply (
select
(
select r.*
from result as r
where r.parent = t.Id
and r.level > 0
order by r.id
for json auto
) as children
) as c
where t.level = 0
order by t.Level
for json auto;
Output
[{
"Id": 1,
"name": "Home",
"rootid": 0,
"level": 0
}, {
"Id": 2,
"name": "Transaction",
"rootid": 0,
"level": 0,
"children": [{
"id": 4,
"name": "Purchase Request",
"rootId": 2,
"parent": 2,
"Level": 1
}, {
"id": 5,
"name": "Purchase Order",
"rootId": 2,
"parent": 2,
"Level": 1
}, {
"id": 6,
"name": "Inventory",
"rootId": 2,
"parent": 2,
"Level": 1
}, {
"id": 7,
"name": "Payment Advice",
"rootId": 2,
"parent": 2,
"Level": 1
}, {
"id": 11,
"name": "Create PR",
"rootId": 4,
"parent": 2,
"Level": 2
}]
}, {
"Id": 3,
"name": "Settings",
"rootid": 0,
"level": 0,
"children": [{
"id": 8,
"name": "Setup",
"rootId": 3,
"parent": 3,
"Level": 1
}, {
"id": 9,
"name": "Budget",
"rootId": 3,
"parent": 3,
"Level": 1
}, {
"id": 10,
"name": "CRC",
"rootId": 3,
"parent": 3,
"Level": 1
}]
}]
Above query is not returning nth json child objects, let say if I have nth level of menu items, Parent have multiple Childs and Childs have multiple Childs like treeview.
Tried #Naveen Arora answer:
select ID,name,'' as id,'' as name from Navigations where id not in (select rootid from Navigations) and rootid=0
union
select B.id,B.name,A.id,A.name from Navigations A join Navigations B on A.rootid=B.id
FOR JSON AUTO;
But output
[{
"ID": 1,
"name": "Home",
"id": 0,
"name": ""
}, {
"ID": 2,
"name": "Transaction",
"id": 4,
"name": "Create PR"
}, {
"ID": 2,
"name": "Transaction",
"id": 5,
"name": "Generate PO"
}, {
"ID": 2,
"name": "Transaction",
"id": 6,
"name": "Create Receipt"
}, {
"ID": 2,
"name": "Transaction",
"id": 7,
"name": "Create Issue Request"
}, {
"ID": 2,
"name": "Transaction",
"id": 8,
"name": "Create Issue Note"
}, {
"ID": 2,
"name": "Transaction",
"id": 9,
"name": "Approve Payment Advice"
}, {
"ID": 3,
"name": "Settings",
"id": 11,
"name": "Navigation Management"
}, {
"ID": 11,
"name": "Navigation Management",
"id": 12,
"name": "Navigation & Form Mapping"
}]
Above output it's not include Childs node. Like in Settings I have Navigation Management -> Navigation & Form Mapping
If the sql server version is 2016 or newer than 2016 then you can use FOR JSON PATH.
Assuming that results are stored in test table. This is just to give you an idea how you can do this, may not give you the exact output but you can change it as per your requirement.
SELECT
t.Id AS 'Id',
t.Name AS 'Name',
children = (
SELECT A.id,A.name from test A join test B on A.rootid=B.id
FOR JSON PATH
)
FROM Test t
FOR JSON PATH;
And if it is older than 2016 then you may refer this.
declare #t table
(
Id int identity,
name varchar(50),
rootid int,
level int
);
insert into #t(name, rootid, level)
values
('Home', 0, 0),('Transaction', 0, 0), ('Settings', 0, 0),
('Create PR', 2, 1), ('Generate PO', 2, 1), ('Create Receipt', 2, 1), ('Create Issue Request', 2, 1), ('Create Issue Note', 2, 1), ('Approve Payment Advice', 2, 1),
('Navigation Management', 3, 1), ('Navigation & Form Mapping', 3, 1);
select * from #t;
;WITH result (id, name, rootId, parent, Level) AS
(
SELECT id,
name,
RootId,
Id as Parent,
0 as Level
FROM #t
WHERE RootId= 0
UNION ALL
SELECT t.id,
t.Name,
t.RootId,
r.Parent,
r.Level + 1
FROM #t t
INNER JOIN result r ON r.id = t.RootId
)
SELECT t.*, json_query(nullif(c.children, '[{}]')) as children
FROM #t as t
outer apply (
select
(
select r.*
from result as r
where r.parent = t.Id
and r.level > 0
order by r.id
for json auto
) as children
) as c
where t.level = 0
order by t.Level
for json auto;
SELECT t.*, json_query(nullif(c.children, '[{}]')) as children
FROM #t as t
outer apply (
select
(
select r.*
from #t as r
where r.rootid = t.Id
and r.level > 0
order by r.id
for json auto
) as children
) as c
where t.level = 0
order by t.Level
for json auto;
My apology for late posting my answer. But I really appreciate the efforts of #Iptr and #NaveenArora answer on my post. After I do some brain storming on my case I've finally found the way to do it.
Create this function:
create function [dbo].[fnUDFCreateJSON](#currentId int)
returns varchar(max)
begin
declare #json nvarchar(max)
IF #currentId <> 0
BEGIN
set #json =
(
select [ID], [Name], CSSClass, RouteURL, json_query(dbo.fnUDFCreateJSON([ID])) as SubNavigation
from dbo.Navigations
where RootId = #currentId
for json auto
);
END
ELSE
BEGIN
set #json =
(
select [ID], [Name], CSSClass, RouteURL, '' as SubNavigation from dbo.Navigations where RootId = 0
for json auto
);
END
return #json
end
and call it by using stored procedure:
CREATE PROCEDURE [dbo].[spGetStartupNavigations]
AS
BEGIN
SELECT
(SELECT
ID, Name, CSSClass, RouteURL,
JSON_QUERY (dbo.fnUDFCreateJSON(ID)) AS SubNavigation
FROM
dbo.Navigations
WHERE
RootId = 0
FOR JSON AUTO) AS Navigation
END
That's it.

N1QL Check if the array contains id

I have a document called
player::id
for each player. Where id is the player's id (auto-incremented).
How can I run search operations on the array below such as checking the id's or count? This array is stored in a player's save document.
"inventory": {
"0": {
"count": 1,
"id": 6
},
"1": {
"count": 1,
"id": 13
},
"2": {
"count": 1,
"id": 142
},
"3": {
"count": 1,
"id": 144
}
},
There is no ARRAY in the object you have posted.
if you want search id 13 is present in the document and get the corresponding count you can use OBJECT_PAIRS() function which convert dynamic object into ARRAY described https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/objectfun.html
SELECT op.val.id, op.val.count, op.name AS pos
FROM default AS d
UNNEST OBJECT_PAIRS(d.inventory) AS op
WHERE op.val.id = 13
OR
SELECT d.*
FROM default AS d
WHERE ANY op IN OBJECT_PAIRS(d.inventory) SATISFIES op.val.id = 13 END;

how to implement sub select with where condition in sequelize

I have these tables:
products
stores
produuctProperties
with this structure
[
"products" :
{
"id": 1,
"orginalName": "146153-0100 ",
"title": null,
"stores": [
{
"id": 1,
"stock": 100,
"minOQ": 1,
"maxOQ": 0
},
{
"id": 2,
"stock": 100,
"minOQ": 1,
"maxOQ": 0,
}
],
"productproperties": [
{
"id": 1,
"productId": 1,
"propertyId": 8,
"propertyOptionId": 5
},
{
"id": 2,
"productId": 1,
"propertyId": 9,
"propertyOptionId": 11
},
{
"id": 3,
"productId": 1,
"propertyId": 10,
"propertyOptionId": 9
}
]
}
]
I want filter my products by selected options , Suppose the selected options are 11 and 9
how to implement below sql query in Sequelize 5.6 with findAll , where and... :
select * from products as p
inner join stores as sr on sr.productId = p.id
where (select count(*) from productProperties where propertyOptionId in (11,9) and productId = p.id) >= 2
I've found that using query builder in sequelize is really confusing,
so if you're good with raw sql you could just run them on as below
if Student is you're model
then
const students = Student.query('Select * from students');

Flatten nested JSON structure in PostgreSQL

I'm trying to write a Postgres query that will output my json data in a particular format.
JSON data structure
{
user_id: 123,
data: {
skills: {
"skill_1": {
"title": "skill_1",
"rating": 4,
"description": 'description text'
},
"skill_2": {
"title": "skill_2",
"rating": 2,
"description": 'description text'
},
"skill_3": {
"title": "skill_3",
"rating": 5,
"description": 'description text'
},
...
}
}
}
This is how I need the data to be formatted in the end:
[
{
user_id: 123,
skill_1: 4,
skill_2: 2,
skill_3: 5,
...
},
{
user_id: 456,
skill_1: 1,
skill_2: 3,
skill_3: 4,
...
}
]
So far I'm working with a query that looks like this:
SELECT
user_id,
data#>>'{skills, "skill_1", rating}' AS "skill_1",
data#>>'{skills, "skill_2", rating}' AS "skill_2",
data#>>'{skills, "skill_3", rating}' AS "skill_3"
FROM some_table
There has to be a better way to go about writing my query. There are 400+ rows and 70+ skills. My above query is a little crazy. Any guidance or help would be greatly appreciated.
Some things to note:
Users rated themselves on 70+ skills
Each skill object has the same structure
Each user rated themselves on the exact same set of skills
db<>fiddle
I expanded your test data to (note the array around all users):
[{
"user_id": 123,
"data": {
"skills": {
"skill_1": {
"title": "skill_1",
"rating": 4,
"description": "description text"
},
"skill_2": {
"title": "skill_2",
"rating": 2,
"description": "description text"
},
"skill_3": {
"title": "skill_3",
"rating": 5,
"description": "description text"
}
}
}
},
{
"user_id": 456,
"data": {
"skills": {
"skill_1": {
"title": "skill_1",
"rating": 1,
"description": "description text"
},
"skill_2": {
"title": "skill_2",
"rating": 3,
"description": "description text"
},
"skill_3": {
"title": "skill_3",
"rating": 4,
"description": "description text"
}
}
}
}]
The query:
SELECT
jsonb_pretty(jsonb_agg(user_id || skills)) -- E
FROM (
SELECT
json_build_object('user_id', user_id)::jsonb as user_id, -- D
json_object_agg(skill_title, skills -> skill_title -> 'rating')::jsonb as skills
FROM (
SELECT
user_id,
json_object_keys(skills) as skill_title, -- C
skills
FROM (
SELECT
(datasets -> 'user_id')::text as user_id,
datasets -> 'data' -> 'skills' as skills -- B
FROM (
SELECT
json_array_elements(json) as datasets -- A
FROM (
SELECT '/* the JSON data; see db<>fiddle */'::json
)s
)s
)s
)s
GROUP BY user_id
ORDER BY user_id
)s
A Make all array elements ({user_id: '42', data: {...}}) one row each
B First column safe the user_id. The cast to text ist necessary for the GROUP BY later which cannot group JSON output. For the second column extract the skills data of the user
C Extract the skill titles for using them as keys in (D.1).
D.1 skills -> skill_title -> 'rating' extracts the rating value from each skill
D.2 json_object_agg aggregates the skill_titles and each corresponding rating value into one JSON object; grouped by the user_id
D.3 json_build_object makes the user_id a JSON object again
E.1 user_id || skills aggregates the two json object into one
E.2 jsonb_agg aggregates these json objects into an array
E.3 jsonb_pretty makes the result looking pretty.
Result:
[{
"skill_1": 4,
"skill_2": 2,
"skill_3": 5,
"user_id": "123"
},
{
"skill_1": 1,
"skill_2": 3,
"skill_3": 4,
"skill_4": 42,
"user_id": "456"
}]