How do I extract values from a jsonb array of objects? - arrays

I am using Postgres and I am trying to get all the elements in the array that's has a keys statusCode and place the values into an array so I can display it.
"systemStatuses": [
{
"changedBy": "monsjenni557",
"timeStamp": 1554151540.9612856,
"statusCode": "S01",
"statusDescription": "Received"
},
{
"changedBy": "monsjenni557",
"timeStamp": 1554151546.2600567,
"statusCode": "SF02",
"statusDescription": "Request Validation Fail"
}
]
the result should be ["S01","SF02"]

You can expand and then aggregate back the jsonb field. The WITH section is only here for example purposes.
WITH exampleData AS (
SELECT '[
{
"changedBy": "monsjenni557",
"timeStamp": 1554151540.9612856,
"statusCode": "S01",
"statusDescription": "Received"
},
{
"changedBy": "monsjenni557",
"timeStamp": 1554151546.2600567,
"statusCode": "SF02",
"statusDescription": "Request Validation Fail"
}
]'::jsonb as regionSales
)
SELECT (
SELECT jsonb_agg( sale -> 'statusCode')
FROM jsonb_array_elements(regionSales) AS sale
)
FROM exampleData

Related

Loading JSON data into snowpipe

we have below Valid JSON data which resides in S3 and we are trying load this data into snowflake table by snowpipe .
"Vendor": {
"string": "ABC"
},
"vmAddresses": [{
"Address": {
"string": "addr1"
},
"Category": {
"string": "order"
}
]
SELECT $1:Vendor.string::varchar,
$1:vmAddresses[0].Address.string,
object_keys($1:vmAddresses[0]),
object_pick($1:vmAddresses[0],'Address', 'Category')
FROM #S3://20210310194308.json
with OBJECT_KEYS we are able to get the keys but unable to get the corresponding value of it . the below format is what we are trying to get
{
"Address": "addr1",
"Category": "order"
}
Any help would be appreciated.
When I tried to validate your sample text trough parse_json and an online json formatter, both of them complained about invalid JSON. I corrected it, and run your SQL:
with json_data as (
select parse_json( '{ "Vendor": {"string": "ABC" }, "vmAddresses": [ { "Address": { "string": "addr1" }, "Category": { "string": "order" } } ] }' ) j)
select j:Vendor.string,
j:vmAddresses[0].Address.string,
object_keys(j:vmAddresses[0]),
object_pick(j:vmAddresses[0],'Address', 'Category')
from json_data;
And it worked as expected:
j:vmAddresses[0].Address.string <-- returns "addr1"
object_keys(j:vmAddresses[0]) <-- returns [ "Address", "Category" ]
j:vmAddresses[0] or object_pick(j:vmAddresses[0],'Address', 'Category') <-- returns
{"Address": { "string": "addr1" }, "Category": { "string": "order" } }
Which value are you trying to parse? Everything seems working.
Additional answers based on comment:
You can use object_construct to build the JSON after reading the values with the vmAddresses[0].Address.string notation:
with json_data as (
select parse_json( '{ "Vendor": {"string": "ABC" }, "vmAddresses": [ { "Address": { "string": "addr1" }, "Category": { "string": "order" } } ] }' ) j)
select OBJECT_CONSTRUCT( 'Address', j:vmAddresses[0].Address.string, 'Category', j:vmAddresses[0].Category.string )
from json_data;

ambiguous column name 'VALUE'

Any idea to overcome ambiguous column with snowflake lateral flatten function error with below logic is much appreciated.
I'm trying to flatten the nested JSON data using the below query by selecting the value from variant column, However getting ambiguous column name 'VALUE' error with lateral flatten function. Can someone help me to achieve the desired output. Issue here is the JSON key name is coming as "value" and I couldn't get that data using lateral flatten. Desired output has been attached as image to this thread.
Sample JSON Data
{"issues": [
{
"expand": "a,b,c,d",
"fields": {
"customfield_10000": null,
"customfield_10001": null,
"customfield_10002": [
{
"id": "1234",
"self": "xxx",
"value": "Test"
}
],
},
"id": "123456",
"key": "K-123"
}
]}*
*select
a.value:id::number as ISSUE_ID,
a.value:key::varchar as ISSUE_KEY,
b.value:id::varchar as ROOT_CAUSE_ID,
**b.value:value::varchar as ROOT_CAUSE_VALUE**
from
abc.table_variant,
lateral flatten( input => payload_json:issues) as a,
lateral flatten( input => a.value:fields.customfield_10002) as b;*
Try
b.value:"value"::varchar
WITH CTE AS
(select parse_json('{"issues": [
{
"expand": "a,b,c,d",
"fields": {
"customfield_10000": null,
"customfield_10001": null,
"customfield_10002": [
{
"id": "1234",
"self": "xxx",
"value": "Test"
}
],
},
"id": "123456",
"key": "K-123"
}
]}')
as col)
select
a.value:id::number as ID,
a.value:key::varchar as KEY,
b.value:id::INT as customfield_10002,
b.value:value::varchar as customfield_10002_value
from cte,
lateral flatten(input => cte.col, path => 'issues') a,
lateral flatten(input => a.value:fields.customfield_10002) b;

cloudant groupby and count number of times a value appears

First time working with a nosql DB and having trouble writing a query that can look in my DB and for a key count the number of time it appears by another key.
For instance if my DB contains
{
"person": "user1",
"status": "good"
},
{
"person": "user1",
"status": "good"
},
{
"person": "user1",
"status": "bad"
},
{
"person": "user2",
"status": "good"
}
would like to know that person1 was good 2 and bad 1 and person2 was only good 1
in sql would do
select person, status, count(*)
from mydb
groupby person, status
or to get it by a user in the db
select person, status, count(*)
from mydb
groupby person, status
where person = "user1"
You can achieve this with Cloudant's MapReduce views and suitably chosen query parameters. I created a view where the map is
function (doc) {
emit([doc.person, doc.status], null);
}
and the reduce the built-in _count. That gives us an index where the key is a vector, and we can then group at different levels. Using groupby=true with group_level=2 gives us the desired result:
curl 'https://A.cloudant.com/D/_design/so/_view/by-status?groupby=true&group_level=2'
{
"rows": [
{
"key": [
"user1",
"bad"
],
"value": 1
},
{
"key": [
"user1",
"good"
],
"value": 2
},
{
"key": [
"user2",
"good"
],
"value": 1
}
]
}

Postgresql get elements of a JSON array

Let's say that we have the following JSON in Postgresql:
{ "name": "John", "items": [ { "item_name": "lettuce", "price": 2.65, "units": "no" }, { "item_name": "ketchup", "price": 1.51, "units": "litres" } ] }
The JSONs are stored in the following table:
create table testy_response_p (
ID serial NOT NULL PRIMARY KEY,
content_json json NOT NULL
)
insert into testy_response_p (content_json) values (
'{ "name": "John", "items": [ { "item_name": "lettuce", "price": 2.65, "units": "no" }, { "item_name": "ketchup", "price": 1.51, "units": "litres" } ] }'
)
Since the following can return either JSON or text (with -> and ->> respectively select content_json ->> 'items' from testy_response_p) I want to use a subquery in order to get elements of the array under items:
select *
from json_array_elements(
select content_json ->> 'items' from testy_response_p
)
All I get is an error but I don't know what I'm doing wrong. The output of the subquery is text. The final output is:
{ "item_name": "lettuce", "price": 2.65, "units": "no" }
{ "item_name": "ketchup", "price": 1.51, "units": "litres" }
You need to join to the function's result. You can't use the ->> operator because that returns text, not json and json_array_elements() only works with a JSON value for its input.
select p.id, e.*
from testy_response_p p
cross join lateral json_array_elements(p.content_json -> 'items') as e;
Online example: https://rextester.com/MFGEA29396

Updating a field with a nested array in Elastic Search

I am trying to update a field in a document with an array. I want to add an array to the field "products". I tried this:
POST /index/type/1/_update
{
"doc" :{
"products": [
{
"name": "A",
"count": 1
},
{
"name": "B",
"count": 2
},
{
"name": "c",
"count": 3
}
]
}
}
this is the error response I am getting when I try and run the code:
{
"error": {
"root_cause": [
{
"type": "mapper_parsing_exception",
"reason": "failed to parse [products]"
}
],
"type": "mapper_parsing_exception",
"reason": "failed to parse [products]",
"caused_by": {
"type": "illegal_state_exception",
"reason": "Can't get text on a START_OBJECT at 1:2073"
}
},
"status": 400
}
Anyone know what I am doing wrong?
The message "Can't get text on a START_OBJECT" means that Elasticsearch was expecting an entry of type "string" but you are trying to give an object as input.
If you check Kibana you will find that the field "products" exists there and is defined as a string. But since you are entering a list of dictionaries then the field "products" should have been defined from the beginning as an object (preferably with dynamic fields in it). An example would be (see full example at https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic.html )
"products": {
"dynamic": true,
"properties": {}
}
However since you already have the index then you can't change the mapping so you would need to delete the index, do the mapping beforehand and then do the update.

Resources