Postgres query array elements inside JSON? - postgresql

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[]

Related

Postgres - jsonb create and update new attribute in column

I have such a column attributes:
{
"a:value": "123",
"a:origin": "abc"
}
I want to create a new attribute which should look like this:
"abcKey:value": {
"value": "123ABC",
"version": "1"
}
So, in the end attributes should look like this:
{
"a:value": "123",
"a:origin": "abc",
"abcKey:value": {
"value": "123ABC",
"version": "1"
}
}
How can I do this?
I tried this
update my_table
set attributes = jsonb_set(attributes, '{abcKey:value,value}', '"123ABC"')
attributes = jsonb_set(attributes, '{abcKey:value,version}', '"1"')
where ...;
But this does not work because I think, I have to create the new attribute at first. How can I create and update this new attribute (maybe in one step)?
Thank you very much!
I wrote two samples for you:
-- if you have same objects are json
with tb as (
select
'{
"a:value": "123",
"a:origin": "abc"
}'::jsonb a1,
'{"abcKey:value": {
"value": "123ABC",
"version": "1"
}}'::jsonb a2
)
select a1, a2, a1||a2 from tb; -- you can concate json objects
-- if you can create json objects via using key value
with tb as (
select
'{
"a:value": "123",
"a:origin": "abc"
}'::jsonb a1
)
select a1 || jsonb_build_object('abcKey:value', jsonb_build_object('value', '123ABC', 'version', 1)) from tb;

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')

Append in jsonb array and update existing record based on a key

I have a table media with a jsonb array field pictures that contains an empty array.
The idea is that every time I append a new json object, I want to switch the default attribute from any previous one from true to false.
Sample object:
{"file": "file.jpg", "default": true}
I accomplished that with 2 different queries.
One for inserting a new record:
update media
set pictures = jsonb_set(
pictures,
concat('{' , jsonb_array_length(pictures) , '}')::text[],
jsonb_build_object('file', 'somepicture.jpg', 'default', true)
)
where user_id = 8
And one for switching from default: true to default:false
update media
set pictures =
(
select
jsonb_agg(
case when value->>'default' = 'true' and value->>'file' != 'somepicture.jpg'
then value || jsonb_build_object('default', false)
else value
end
)
from jsonb_array_elements(media.pictures)
)
where user_id = 8
My final pictures array:
[
{
"file": "previouspicture.jpg",
"default": false
},
{
"file": "somepicture.jpg",
"default": true
}
]
How can I achieve the same thing, with only one query?
Use an extra jsonb_set() to update the previous object. You have to use coalesce() to be able to start with an empty array:
update media
set pictures = jsonb_set(
coalesce(
jsonb_set(
pictures,
array[(jsonb_array_length(pictures)-1)::text],
pictures->jsonb_array_length(pictures)-1 || '{"default": false}'
),
pictures
),
array[(jsonb_array_length(pictures))::text],
jsonb_build_object('file', 'filename.jpg', 'default', true)
)
where user_id = 8
returning *;
DbFiddle.

Retrieve UserName from ServiceNow

I am able to retrieve records for a particular Incident ID using Invoke-RestMethod. However, while retrieving the data, values like Resolved To, Updated By, etc. get populated by a sysid.
Resolved By comes in this format:
https<!>://devinstance.servicenow.com/api/sysid, value= sysid
I would like to view the username instead of the sysid.
The 'User ID' (user_name) isn't on the Incident, it's on the sys_user table, so you'll have to dot-walk to it.
If you're using the table API, you'll need to specify a dot-walked field to return, using the sysparm_fields query parameter.
This is no problem, just specify your endpoint like this:
$uri = "https://YOUR_INSTANCE.service-now.com/api/now/table/incident?sysparm_query=number%3DINC0000001&sysparm_fields=resolved_by.user_name"
I've specified a query for a specific incident number is requested, but you can replace that with whatever your query is.The important part is sysparm_fields=resolved_by.user_name. You'll want to specify any other fields you need here, as well.
The JSON I get as a result of running this API call, is the following:
{
"result": [
{
"resolved_by.user_name": "admin"
}
]
}
Note the element name: "resolved_by.user_name".
Another option for doing this, would be to tell the API to return both display, and actual values by specifying the sysparm_display_value parameter and setting it to all to return both sys_id and display value, or just true to return only display values.
Your URI would then look like this:
https://dev12567.service-now.com/api/now/table/incident?sysparm_query=resolved_byISNOTEMPTY%5Enumber%3DINC0000001&sysparm_display_value=all
And your JSON would contain the following:
"number": {
"display_value": "INC0000001",
"value": "INC0000001"
},
"resolved_by": {
"display_value": "System Administrator",
"link": "https://YOUR_INSTANCE.service-now.com/api/now/table/sys_user/6816f79cc0a8016401c5a33be04be441",
"value": "6816f79cc0a8016401c5a33be04be441"
},
"sys_updated_by": {
"display_value": "admin",
"value": "admin"
},
This would be accessed by:
answer.result[n].resolved_by.display_value

How do I create a Lithium - form->select from controller output

I want to create a dropdown for types collection from MongoDB, in my MongoDB collection:
section has types and controller code with view code. I want to create a form->select from the output of the controller.
types
{
"_id": ObjectId("5082c6109d5d0c640c000000"),
"name": "JACKET CLUSTER FRONT"
}
{
"_id": ObjectId("5082c62b9d5d0c440c00006e"),
"name": "JACKET CLUSTER FRONT"
}
{
"_id": ObjectId("5082c62b9d5d0c440c00006f"),
"name": "TITLE WITHOUT SYMBOL"
}
{
"_id": ObjectId("5082c62b9d5d0c440c000070"),
"name": "FRONTISPIECE"
}
*/
// in my controller
// -----------
$types = Types::all(array('order'=>'_id'));
$vtype = array($types)
return compact('vtypes');
// in my view
// ------------------
echo $this->form->select('types',$vtypes);
find('list') returns a key/value array, useful for any use where you would want a list such as for populating input select boxes.
$types = Types::find('list')
//returns
Array
(
[5082c6109d5d0c640c000000] => 'JACKET CLUSTER FRONT',
[5082c62b9d5d0c440c00006e] => 'JACKET CLUSTER FRONT',
[5082c62b9d5d0c440c00006f] => 'TITLE WITHOUT SYMBOL',
...
)
This finder looks for $_meta['title'] of your model, which is by default name if this field is available, and $_meta['key'] for the id, which should be _id in your case if your schema is correct
Finally, I used this to achieve the result.
Types::meta('key', '_id');
Types::meta('title', 'filename');
$types = Types::find('list',array(
'fields'=>array('id','filename'),
'order'=>'id'));