Remove the wrapping of json_buid_object in postgresql - postgresql

This is the query of the postgresql.This returns each object wrapped with json_build_object.How to remove the wrapper of json_build_object and just return it without any wrapper in Postgresql.
let sql = `SELECT json_build_object 'id',Y."Id", 'name',Y."name", 'is_enabled',Y."is_enabled", 'is_setup_complete',Y."is_setup_complete", 'approval_time',Y."approval_time", )
"shops": [
{
"json_build_object": {
"id": 1,
"name": "Melody Garments",
"is_enabled": true,
"is_setup_complete": false,
"approval_time": 10,
"packaging_time": 30,```

Since it looks like your client library is already converting results to JSON, you probably don't need json_build_object at all but instead can use column aliases to control the keys.
SELECT Y."Id" as id, Y."name" as name ...

Related

sequelize, query property on array of objects

I have looked extensively for an answer but could not find a simple solution.
I have a table that contains a column subscriptionHistory
The data can look like so:
[
{
"fromDate": "2023-01-24T10:11:57.150Z",
"userSubscribedToo": "EuuQ13"
},
{
"fromDate": "2022-01-24T10:11:57.150Z",
"tillDate": "2022-02-24T22:59:59.999Z",
"userSubscribedToo": "a4ufoAB"
}
]
I'm trying to find the records of the subscriptions.
In Mongo we do
'subscriptionHistory.$.userSubscribedToo' = 'a4ufoAB'
Nice and easy.
I'm using PostgreSQL and Sequelize,
The following doesn't work.
const totalEarnings = await SubscriptionToken.count({
where: {
'subscriptionHistory.$.userSubscribedToo': user.id,
},
});
Neither do any direct queries
SELECT *
FROM vegiano_dev."subscription-tokens"
WHERE "subscriptionHistory"->>'userSubscribedToo' = 'a4ufoAB'
--WHERE "subscriptionHistory" #> '{"userSubscribedToo": "a4ufoAB"}'
Not sure where to go now :-/
You can use a JSON path condition with the ## (exists) operator:
select *
from vegiano_dev."subscription-tokens"
where "subscriptionHistory" ## '$[*].userSubscribedToo == "a4ufoAB"'
The #> will work as welll, but because subscriptionHistory is an array, you need to use an array with that operator:
where "subscriptionHistory" #> '[{"userSubscribedToo": "a4ufoAB"}]'
This assumes that subscriptionHistory is defined as jsonb which it should be. If it's not, you need to cast it: "subscriptionHistory"::jsonb

Sort by json element at nested level for jsonb data - postgresql

I have below table in postgresql which stored JSON data in jsonb type of column.
CREATE TABLE "Trial" (
id SERIAL PRIMARY KEY,
data jsonb
);
Below is the sample json structure
{
"id": "000000007001593061",
"core": {
"groupCode": "DVL",
"productType": "ZDPS",
"productGroup": "005001000"
},
"plants": [
{
"core": {
"mrpGroup": "ZMTS",
"mrpTypeDesc": "MRP",
"supLeadTime": 777
},
"storageLocation": [
{
"core": {
"storageLocation": "H050"
}
},
{
"core": {
"storageLocation": "H990"
}
},
{
"core": {
"storageLocation": "HM35"
}
}
]
}
],
"discriminator": "Material"
}
These are the scripts for insert json data
INSERT INTO "Trial"(data)
VALUES(CAST('{"id":"000000007001593061","core":{"groupCode":"DVL","productType":"ZDPS","productGroup":"005001000"},"plants":[{"core":{"mrpGroup":"ZMTS","mrpTypeDesc":"MRP","supLeadTime":777},"storageLocation":[{"core":{"storageLocation":"H050"}},{"core":{"storageLocation":"H990"}},{"core":{"storageLocation":"HM35"}}]}],"discriminator":"Material"}' AS JSON))
INSERT INTO "Trial"(data)
VALUES(CAST('{"id":"000000000104107816","core":{"groupCode":"ELC","productType":"ZDPS","productGroup":"005001000"},"plants":[{"core":{"mrpGroup":"ZCOM","mrpTypeDesc":"MRP","supLeadTime":28},"storageLocation":[{"core":{"storageLocation":"H050"}},{"core":{"storageLocation":"H990"}}]}],"discriminator":"Material"}' AS JSON))
INSERT INTO "Trial"(data)
VALUES(CAST('{"id":"000000000104107818","core":{"groupCode":"DVK","productType":"ZDPS","productGroup":"005001000"},"plants":[{"core":{"mrpGroup":"ZMTL","mrpTypeDesc":"MRP","supLeadTime":28},"storageLocation":[{"core":{"storageLocation":"H050"}},{"core":{"storageLocation":"H990"}}]}]}' AS JSON))
If try to sort by at first level then it works
select id,data->'core'->'groupCode'
from "Trial"
order by data->'core'->'groupCode' desc
But when I try to sort by at nested level, below is the script then it doesn't work for me, I'm for sure I'm wrong for this script but don't know what is it ? Need assistant if someone knows how to order by at nested level for JSONB data.
select id,data->'plants'
from sap."Trial"
order by data->'plants'->'core'->'mrpGroup' desc
Need assistance for write a query for order by at nested level for JSONB data.
Below query works for me
SELECT id, data FROM "Trial" ORDER BY jsonb_path_query_array(data, '$.plants[*].core[*].mrpGroup') desc limit 100

Insert new item in JSONB column based on value of other field - postgres

I have the following jsonb structure with many entries in it
[
{
"name":"test",
"features":[
{
"name":"feature1",
"granted":false
},
{
"name":"feature2",
"granted":true
}
]
}...
]
I'd like to add a new entry in the features array when the parent name element has value "test" and feature1 granted is "false".
The idea is to write a flyway script to migrate my data.
I've been battling with jsonb_insert but I can't figure out the path portion of it since I can have potentially many elements in there and I can't just add a given subscript.
End result should be:
[
{
"name":"test",
"features":[
{
"name":"feature1",
"granted":false
},
{
"name":"feature2",
"granted":true
},
{
"name":"newFeature",
"granted":false
}
]
}
]
EDIT1
So far I've attempted:
UPDATE my_table SET modules =
jsonb_insert(my_column, '{features, [0]}', '{"name": "newFeature", "granted": false}')
WHERE my_column ->> 'name' = 'test' AND my_column #> '{"features": [{"name":"feature1", "granted": false}]}';
The statement executes but no updates are actually done.
EDIT2
I modified the query just to test the PATH out to
UPDATE my_table SET modules =
jsonb_insert(my_column, '{0, features, 0}', '{"name": "newFeature", "granted": false}')
WHERE my_column ->> 'name' = 'test' AND my_column #> '{"features": [{"name":"feature1", "granted": false}]}';
However this only always updates the first entry in the array, and the object I need to update is not guaranteed to always be in this position
This should be enough information to complete the query:
Let's create the mock data
create table a (id serial primary key , b jsonb);
insert into a (b)
values ('[
{
"name": "test",
"features": [
{
"name": "feature1",
"granted": false
},
{
"name": "feature2",
"granted": true
}
]
},
{
"name": "another-name",
"features": [
{
"name": "feature1",
"granted": false
},
{
"name": "feature2",
"granted": true
}
]
}
]');
Now explode the array using jsonb_array_elements with ordinality to get the index and the property
select first_level.id, position, feature_position, feature
from (select a.id, arr.*
from a,
jsonb_array_elements(a.b) with ordinality arr (elem, position)
where elem ->> 'name' = 'test') first_level,
jsonb_array_elements(first_level.elem -> 'features') with ordinality features (feature, feature_position);
The result of this query is:
1,1,1,"{""name"": ""feature1"", ""granted"": false}"
1,1,2,"{""name"": ""feature2"", ""granted"": true}"
There you have the necessary info that you need to fetch the sub elements that you need, as well as all the indexes that you needed for your query.
Now, to the final edit, you already had the query that you wanted:
UPDATE my_table SET modules =
jsonb_insert(my_column, '{0, features, 0}', '{"name": "newFeature", "granted": false}')
WHERE my_column ->> 'name' = 'test' AND my_column #> '{"features": [{"name":"feature1", "granted": false}]}';
In the where you'll use the id, because those are the rows that you are interested in, and in the indexes you got them from the query. So:
UPDATE my_table SET modules =
jsonb_insert(my_column, '{' || exploded_info.position::string || ', features, ' || exploded_info.feature_position || '}', '{"name": "newFeature", "granted": false}') from (/* previous query */) as exploded_info
WHERE exploded_info.id = my_table.id and exploded_info.feature -> 'granted' = false;
As you can see this easily get's very nasty.
I'd recommend either using a more sql approach, that is, having features in a table instead of inside a json, a fk linking that to your table...
If you really need to use the json, for example, because the domain is really complex and defined at the application level and very flexible. Then I would recommend doing the updates inside app code

Postgres query array elements inside JSON?

I have Postgres 11 table called fb_designs that has a json column with data structured like so:
{
"listings": [
{
"id": "KTyneMdrAhAEKyC9Aylf",
"active": true
},
{
"id": "ZcjK9M4tuwhWWdK8WcfX",
"active": false
}
]
}
and a tags column in a character varying[] format as so {dWLaRWChaThFPH6b3BpA,BrYiPaUiou020hsmRugR}. Both lengths are undefined.
What I am trying to do is produce a some queries that will let me say in laymans terms,
show me all results where at all items.listings has an
active status and tags contains BrYiPaUiou020hsmRugR
I got this far, however I'm not sure how to add in WHERE uid = "foo", WHERE tags contains "foo", "bar and WHERE title is like %hoot%
SELECT id, title, tags, selected_preview_image, items
FROM fb_designs r, json_array_elements(r.items#>'{listings}') obj
WHERE obj->>'active' = 'true'
GROUP BY id
If they are all true, then none of them are false. Sounds like you want to negate the containment operation over false.
select * from fb_designs where
not items::jsonb #> '{"listings":[{"active": false}]}'
and tags && ARRAY['BrYiPaUiou020hsmRugR']::varchar[]

Creating an AND query on a list of items in Azure Cosmos

I'm building an application in Azure Cosmos and I'm having trouble creating a query. Using the dataset below, I want to create a query that only finds CharacterId "Susan" by searching for all characters that have the TraitId of "Athletic" and "Slim".
Here is my JSON data set
{
"characterId": "Bob",
"traits": [
{
"traitId": "Athletic",
"traitId": "Overweight"
}
],
},
{
"characterId": "Susan",
"traits": [
{
"traitId": "Athletic",
"traitId": "Slim"
}
],
},
{
"characterId": "Jerry",
"traits": [
{
"traitId": "Slim",
"traitId": "Strong"
}
],
}
]
The closest I've come is this query but it acts as an OR statement and what I want is an AND statement.
SELECT * FROM Characters f WHERE f.traits IN ("Athletic", "Slim")
Any help is greatly appreciated.
EDITED: I figured out the answer to this question. If anyone is interested this query gives the results I was looking for:
SELECT * FROM Characters f
WHERE EXISTS (SELECT VALUE t FROM t IN f.traits WHERE t.traitId = 'Athletic')
AND EXISTS (SELECT VALUE t FROM t IN f.traits WHERE t.traitId = 'Slim')
The answer that worked for me is to use EXISTS statements with SELECT statements that searched the traits list. In my program I can use StringBuilder to create a SQL statement that concatenates an AND EXISTS statement for each of the traits I want to find:
SELECT * FROM Characters f
WHERE EXISTS (SELECT VALUE t FROM t IN f.traits WHERE t.traitId = 'Athletic')
AND EXISTS (SELECT VALUE t FROM t IN f.traits WHERE t.traitId = 'Slim')