APEX_JSON get array object - oracle

declare
l_json_doc VARCHAR2(32767);
l_numcols number;
l_numrows number;
begin
l_json_doc := '{
"table": {
"name": "sometablename",
"numofcolumns": 5,
"numofrows": 5,
"colheadings": [{
"colname": "customcol1",
"coltype": "number"
},
{
"colname": "customcol2",
"coltype": "varchar2"
},
{
"colname": "customcol3",
"coltype": "varchar2"
},
{
"colname": "customcol4",
"coltype": "varchar2"
},
{
"colname": "customcol5",
"coltype": "number"
}
],
"data": [{
"customcol1": "datacolumn1",
"customcol2": "datacolumn2",
"customcol3": "datacolumn3",
"customcol4": "datacolumn4",
"customcol5": "datacolumn5"
},
{
"customcol1": "2datacolumn1",
"customcol2": "2datacolumn2",
"customcol3": "2datacolumn3",
"customcol4": "2datacolumn4",
"customcol5": "2datacolumn5"
},
{
"customcol1": "3datacolumn1",
"customcol2": "3datacolumn2",
"customcol3": "3datacolumn3",
"customcol4": "3datacolumn4",
"customcol5": "3datacolumn5"
},
{
"customcol1": "4datacolumn1",
"customcol2": "4datacolumn2",
"customcol3": "4datacolumn3",
"customcol4": "4datacolumn4",
"customcol5": "4datacolumn5"
}
]
}
}';
APEX_JSON.parse(l_json_doc);
l_numcols := APEX_JSON.get_count(p_path => 'table.colheadings');
l_numrows := APEX_JSON.get_count(p_path => 'table.data');
FOR i IN 1 .. l_numrows LOOP
FOR j IN 1 .. l_numcols LOOP
dbms_output.put_line('TEST ' || APEX_JSON.get_varchar2(p_path => 'table.data[%d]') );
END LOOP;
END LOOP;
end;
This is my code which is supposed to extract the data array objects. I expect the following output:
TEST {"customcol1": "datacolumn1","customcol2": "datacolumn2","customcol3": "datacolumn3","customcol4": "datacolumn4","customcol5": "datacolumn5"}
TEST { "customcol1": "2datacolumn1","customcol2": "2datacolumn2","customcol3": "2datacolumn3","customcol4": "2datacolumn4","customcol5": "2datacolumn5"}
etc ...
But when I try to get the json object from the data array using the APEX_JSON.get_varchar2 it returns empty

Two problems with the code there
You have not provided an index to the get_varchar2 function. So the path is not complete. You need to provide a value in the p0 parameter of that function
That's not how APEX_JSON.get_varchar2 works. You are expecting the
function to return the entire JSON object in the data array but get_varchar2 cannot do that. It can only get you the VALUE that is a VARCHAR at a specified path. It cannot get you the entire object.
For your output
DECLARE
l_json_doc VARCHAR2 (32767);
l_numcols NUMBER;
l_numrows NUMBER;
v_colname VARCHAR2 (32767);
BEGIN
l_json_doc := '{
"table": {
"name": "sometablename",
"numofcolumns": 5,
"numofrows": 5,
"colheadings": [{
"colname": "customcol1",
"coltype": "number"
},
{
"colname": "customcol2",
"coltype": "varchar2"
},
{
"colname": "customcol3",
"coltype": "varchar2"
},
{
"colname": "customcol4",
"coltype": "varchar2"
},
{
"colname": "customcol5",
"coltype": "number"
}
],
"data": [{
"customcol1": "datacolumn1",
"customcol2": "datacolumn2",
"customcol3": "datacolumn3",
"customcol4": "datacolumn4",
"customcol5": "datacolumn5"
},
{
"customcol1": "2datacolumn1",
"customcol2": "2datacolumn2",
"customcol3": "2datacolumn3",
"customcol4": "2datacolumn4",
"customcol5": "2datacolumn5"
},
{
"customcol1": "3datacolumn1",
"customcol2": "3datacolumn2",
"customcol3": "3datacolumn3",
"customcol4": "3datacolumn4",
"customcol5": "3datacolumn5"
},
{
"customcol1": "4datacolumn1",
"customcol2": "4datacolumn2",
"customcol3": "4datacolumn3",
"customcol4": "4datacolumn4",
"customcol5": "4datacolumn5"
}
]
}
}';
APEX_JSON.parse (l_json_doc);
l_numcols := APEX_JSON.get_count (p_path => 'table.colheadings');
l_numrows := APEX_JSON.get_count (p_path => 'table.data');
FOR i IN 1 .. l_numrows
LOOP
DBMS_OUTPUT.put ('TEST {');
FOR j IN 1 .. l_numcols
LOOP
v_colname :=
apex_json.get_varchar2 ('table.colheadings[%d].colname', j);
DBMS_OUTPUT.put (
'"' || v_colname || '":"'
|| APEX_JSON.get_varchar2 (
p_path => 'table.data[%d].' || v_colname,
p0 => i)
|| '",');
END LOOP;
DBMS_OUTPUT.put_line ('}');
END LOOP;
END;
Here is the output of the code:
TEST {"customcol1":"datacolumn1","customcol2":"datacolumn2","customcol3":"datacolumn3","customcol4":"datacolumn4","customcol5":"datacolumn5",}
TEST {"customcol1":"2datacolumn1","customcol2":"2datacolumn2","customcol3":"2datacolumn3","customcol4":"2datacolumn4","customcol5":"2datacolumn5",}
TEST {"customcol1":"3datacolumn1","customcol2":"3datacolumn2","customcol3":"3datacolumn3","customcol4":"3datacolumn4","customcol5":"3datacolumn5",}
TEST {"customcol1":"4datacolumn1","customcol2":"4datacolumn2","customcol3":"4datacolumn3","customcol4":"4datacolumn4","customcol5":"4datacolumn5",}
NOTE: I didn't care to remove the final comma after the last key:value pair in each row. If you want that then you have to store all the key value pairs in a variable and RTRIM the comma out.

Related

How to read values from nested dataset in TFDMongoQuery

I'm reading data from a MongoDB. Here is the data:
[{
"_id": "100",
"v": [
{
"length": 1,
"path": "1.txt"
},
{
"length": 2,
"path": "2.txt"
},
{
"length": 3,
"path": "3.txt"
},
{
"length": 4,
"path": "4.txt"
}
]
}]
It is easy to read _id but not 1.txt, 2.txt and 3.txt. Here is my code:
// fdMongQuery = TFDMongoQuery
// dataset = TDataset
fdMongQuery.Close;
fdMongQuery.FieldDefs.Clear;
fdMongQuery.Connection := fdCon;
fdMongQuery.DatabaseName := 'DATABASE';
fdMongQuery.CollectionName := 'COLLECTION';
fdMongQuery.QMatch := '{_id:"100"}';
fdMongQuery.QSort := '';
fdMongQuery.Open;
// read of id
memoLogs.Lines.Add(fdMongQuery.FieldByName('_id').AsString);
// read of detail
dataset := TDataSetField(fdMongQuery.FieldByName('v')).NestedDataSet;
while not dataset.Eof do
begin
memoLogs.Lines.Add(dataset.Fields[0].AsString);
// output is:
// (1, 1.txt)
// (2, 2.txt)
// (3, 3.txt)
dataset.Next;
end;
I am expecting dataset.Fields[0].AsString should ouput 1 while dataset.Fields[1].AsString should output 1.txt but sadly no. So how can I read the path values?

Trino count query for array

I have a JSON value for a column which is array of objects. Here, my requirement is to find the count of objects matching the filter
Row 1: Coumn 1
{
"createdBy": 2,
"teams": [
{
"companyId" : 1,
"teamId": 1
},
{
"companyId" : 1,
"teamId": 2
}
]
}
Row 2: Coumn 1
{
"createdBy": 2,
"teams": [
{
"companyId" : 1,
"teamId": 3
},
{
"companyId" : 1,
"teamId": 4
}
]
}
Here, companyId 1 presents in 4 places and i need the query to get the count.
Query tried,
select count(1) from a where any_match(
split(
trim(
'[]'
FROM
json_query(
a.teams,
'lax $.companyId' WITH ARRAY WRAPPER
)
),
',"'
),
x -> trim(
'"'
FROM
x
) = 2
)
Here it returns 1 because of any_match. Not sure how to get the size.

How to use apex_json.get_count in a nested array

I am trying to loop through the array from the count of the benefits element in my json. I keep getting numeric value error although get count function in apex json returns a number.
If we change the loop to for 1 in 1..2 - it works fine.
If we hardcode the array index to 1 then the code works but if we try to pass a variable using %d p0 then i get a numeric value error - ORA - 06502.
Below is the code:
j apex_json.t_values;
l_count_chg number;
l_count_pers number;
l_count_ben number;
l_members wwv_flow_t_varchar2;
l_paths apex_t_varchar2;
l_paths2 apex_t_varchar2;
l_paths3 apex_t_varchar2;
v_get_person varchar2(10);
v_get_benefit varchar2(10);
v_get_benopt varchar2(10);
r_count number;
begin
apex_json.parse(j,'{
"PolicyUpdate": {
"contractNumber": 12345,
"effectiveDate": "2022-04-01",
"planChanges": [
{
"changeCode": 1,
"roleplayerId": "pers1",
"person": {
"id": "pers1",
"surname": "Hazy",
"firstName": "Smith",
"benefits": [
{
"Id": "ben1",
"typeCode": "C1",
"benefitName": "Funeral Benefit",
"roleplayerId": "pers1",
"coverAmount": 10000,
"premiumAmount": 47.47,
"StartDate": "2021-04-01",
"Options": {
"Option": [
{
"Label": "Risk Benefit Classification",
"Value": "Main Life"
},
{
"Label": "Waiting Period (DOC to Event)",
"Value": "6 Months"
},
{
"Label": "Paid Up Benefit (Y/N)",
"Value": "No"
}
]
}
},
{
"Id": "ben2",
"typeCode": "C1",
"benefitName": "Tombstone Benefit",
"roleplayerId": "pers1",
"coverAmount": 5000,
"premiumAmount": 10.47,
"StartDate": "2021-04-01"
}
]
}
},
{
"changeCode": 2,
"roleplayerId": "pers2"
}
]
}
}');
dbms_output.put_line('Contract Number : ' ||
apex_json.get_varchar2(p_path => 'PolicyUpdate.contractNumber'));
dbms_output.put_line('Effective Adte : ' ||
apex_json.get_varchar2(p_path => 'PolicyUpdate.effectiveDate'));
dbms_output.put_line('----------------------------------------');
l_count_chg := apex_json.get_count(p_path => 'PolicyUpdate.planChanges',p_values=>j);
dbms_output.put_line('change count '||l_count_chg);
for i in 1..l_count_chg loop
dbms_output.put_line('changeCode '||apex_json.get_varchar2(p_path => 'PolicyUpdate.planChanges[%d].changeCode' ,p_values=>j,p0 => i));
dbms_output.put_line('roleplayerId '||apex_json.get_varchar2(p_path => 'PolicyUpdate.planChanges[%d].roleplayerId',p_values=>j,p0 => i));
dbms_output.put_line('firstname '||apex_json.get_varchar2(p_path => 'PolicyUpdate.planChanges[%d].person.firstName',p_values=>j,p0 => i));
l_count_ben := apex_json.get_count(p_path => 'PolicyUpdate.planChanges[%d].person.benefits',p_values=>j);
dbms_output.put_line('benefit count '|| l_count_ben);
for x in 1..l_count_ben loop
dbms_output.put_line('ben id '||apex_json.get_varchar2(p_path => 'PolicyUpdate.planChanges[%d].person.benefits[%d].Id',p_values=>j,p0 => i,p1 => x));
end loop;
end loop;
end;
For me the count didn't return a number (just no value) so I made some changes - I found it safest to check if the path exists before getting the count:
declare
j apex_json.t_values;
l_count_chg number;
l_count_pers number;
l_count_ben number;
l_members wwv_flow_t_varchar2;
l_paths apex_t_varchar2;
l_paths2 apex_t_varchar2;
l_paths3 apex_t_varchar2;
v_get_person varchar2(10);
v_get_benefit varchar2(10);
v_get_benopt varchar2(10);
r_count number;
begin
apex_json.parse(j,'{
"PolicyUpdate": {
"contractNumber": 12345,
"effectiveDate": "2022-04-01",
"planChanges": [
{
"changeCode": 1,
"roleplayerId": "pers1",
"person": {
"id": "pers1",
"surname": "Hazy",
"firstName": "Smith",
"benefits": [
{
"Id": "ben1",
"typeCode": "C1",
"benefitName": "Funeral Benefit",
"roleplayerId": "pers1",
"coverAmount": 10000,
"premiumAmount": 47.47,
"StartDate": "2021-04-01",
"Options": {
"Option": [
{
"Label": "Risk Benefit Classification",
"Value": "Main Life"
},
{
"Label": "Waiting Period (DOC to Event)",
"Value": "6 Months"
},
{
"Label": "Paid Up Benefit (Y/N)",
"Value": "No"
}
]
}
},
{
"Id": "ben2",
"typeCode": "C1",
"benefitName": "Tombstone Benefit",
"roleplayerId": "pers1",
"coverAmount": 5000,
"premiumAmount": 10.47,
"StartDate": "2021-04-01"
}
]
}
},
{
"changeCode": 2,
"roleplayerId": "pers2"
}
]
}
}');
dbms_output.put_line('Contract Number : ' ||
apex_json.get_varchar2(p_path => 'PolicyUpdate.contractNumber',p_values => j));
dbms_output.put_line('Effective Adte : ' ||
apex_json.get_varchar2(p_path => 'PolicyUpdate.effectiveDate',p_values => j));
dbms_output.put_line('----------------------------------------');
l_count_chg := apex_json.get_count(p_path => 'PolicyUpdate.planChanges',p_values=>j);
dbms_output.put_line('change count '||l_count_chg);
for i in 1..l_count_chg loop
dbms_output.put_line('changeCode '||apex_json.get_varchar2(p_path => 'PolicyUpdate.planChanges[%d].changeCode' ,p_values=>j,p0 => i));
dbms_output.put_line('roleplayerId '||apex_json.get_varchar2(p_path => 'PolicyUpdate.planChanges[%d].roleplayerId',p_values=>j,p0 => i));
dbms_output.put_line('firstname '||apex_json.get_varchar2(p_path => 'PolicyUpdate.planChanges[%d].person.firstName',p_values=>j,p0 => i));
IF apex_json.does_exist(p_path => 'PolicyUpdate.planChanges[%d].person.benefits',p0 => i,p_values=>j) THEN
l_count_ben := apex_json.get_count(p_path => 'PolicyUpdate.planChanges[%d].person.benefits',p0 => i,p_values=>j);
dbms_output.put_line('benefit count '|| l_count_ben);
for x in 1..l_count_ben loop
dbms_output.put_line('ben id '||apex_json.get_varchar2(p_path => 'PolicyUpdate.planChanges[%d].person.benefits[%d].Id',p_values=>j,p0 => i,p1 => x));
end loop;
END IF;
end loop;
end;
Koen's suggestion of testing with EXISTS is excellent.
He also added this, but didn't spell out that your original version seemed to be missing the parameter:
p0 => i
when calculating l_count_ben
So the get_count value would have been unknown.

Parse JSON array APEX_JSON in PL SQL

I have the following JSON object -
{
"items": [
{
"tableName": "contacts",
"count": 1,
"columnNames": [
"id"
],
"rows": [
[
"45"
]
]
}
],
"links": [
{
"rel": "self",
},
{
"rel": "describedby",
}
]
}
I am trying to extract the value from rows- I need the value 45.
I tried to extract using -
row_id := apex_json.get_number ('rows[%d]', 1);
How I can extract it?
Thanks in advance.
Here's an example:
declare
l_json_val apex_json.t_values;
l_clob clob;
l_row_val varchar2(255);
begin
l_clob := q'-
{
"items": [
{
"tableName": "contacts",
"count": 1,
"columnNames": [
"id"
],
"rows": [
[
"45"
]
]
}
],
"links": [
{
"rel": "self",
},
{
"rel": "describedby",
}
]
}
-';
apex_json.parse(p_values => l_json_val, p_source => l_clob, p_strict => false);
l_row_val := apex_json.get_varchar2(p_path => 'items[1].rows[1][1]', p_values => l_json_val);
dbms_output.put_line(l_row_val);
end;
Note that the path expressions with apex_json use a 1 base array index, not 0.

Angular7 : How to correctly map data when subscribing to Observable if Model differ from JSON

I am making a GET request to a REST API. My class Model differ a bit from the JSON requested, and I doesn't seem to be able to get any data : When I log into console my Model object is undefined. How do I correctly map values when subscribing to observable ?
My Model :
export class Signalement {
idsignalement: number;
destinataire_id: number;
idstatut: number;
iddomaine: number;
idlocalisation: number;
idtype: number;
idemetteur: number;
x: number;
y: number;
nom: string;
description: string;
descriptionlieu: string;
la_date: string;
}
My JSON :
{
"_embedded": {
"signalements": [
{
"idsignalement": 1,
"iddomaine": 1,
"idlocalisation": 1,
"idtype": 1,
"idemetteur": 1,
"idstatut": 1,
"x": 1,
"y": 1,
"nom": "Postman Signalement",
"description": "Envoie depuis postman",
"descriptionlieu": "Sur la VM",
"la_date": "2019-02-08T09:25:36.968+0000",
"_links": {
"self": {
"href": "***/signalements/1"
},
"signalement": {
"href": "***/signalements/1"
},
"destinataire": {
"href": "**/signalements/1/destinataire"
}
}
}
]
},
"_links": {
"self": {
"href": "***:8080/signalements{?page,size,sort}",
"templated": true
},
"profile": {
"href": "http://***/profile/signalements"
}
},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
My component :
export class SignalementsComponent implements OnInit {
signalements: Signalement[];
constructor(private signalementService: SignalementService, private messageService: MessageService) { }
ngOnInit() {
this.getSignalements();
}
getSignalements(): void {
this.signalementService.getSignalements().subscribe((data) => {
this.signalements = data;
});
}
My Service :
export class SignalementService {
constructor(private http: HttpClient) { }
getSignalements(): Observable<Signalement[]> {
return this.http.get<Signalement[]>(href);
}
}
You cannot do return this.http.get<Signalement[]>(href); because the data you receive is not a Signalement object.
Keep in mind that javascript is not typed, so the type indications you put in Typescript are just helpers for your coding, not actual enforced rules.
Given the schema of your answers, you should first dig in _embedded field. So you should do:
return this.http.get<Signalement[]>.pipe(map(data => data['_embedded']['signalments']));
You should also add checks to verify fields are indeed present and in the correct format to avoid security issues depending on the potential data source, etc.

Resources