Get json with pljson & plsql - plsql

I'm trying to chop out some lists from the following json using pljson
my_json := json('{"Order":
{"no": 1, "batch": 2,"id": 3,"quantity": 10,
"sm_pack": [
{
"no": 10,
"id": 1010,
"quantity": 2
},
{
"no": 11,
"id": 1040,
"quantity": 8
}
],
"sm_size": [
{ ....etc etc
However, I can't get it to work?
I can print the data using this syntax:
v_myjson.path('Order.sm_pack').print;
v_myjson.path('Order.sm_pack[1].no').print;
But how can I assing all those different lists to variables for further processing. i tried different versions of "v_list := json_list(my_json.get('Order.sm_pack')) .. my_json.get('sm_pack').. whatever I try its"NULL SELF" and I seem to have turned blind.
Regards

Printing json lists and objects differs from assigning them to some variables to manipulate them. I will try to answer your question through your example as follows:
DECLARE
obj json := json();
obj_1 json := json();
arr json_list := json_list();
val NUMBER;
BEGIN
/*Create your object*/
obj := json('{"Order":{"no":1,"batch":2,"id":3,"quantity":10,"sm_pack":[{"no":10,"id":1010,"quantity":2},{"no":11,"id":1040,"quantity":8}],"sm_size":[{"no":10,"id":1010,"quantity":2},{"no":11,"id":1040,"quantity":8}]}}');
/*Assign object*/
obj_1 :=json(obj.get('Order'));
/*Assign list from within the object*/
arr := json_list(obj_1.get('sm_pack'));
arr.print;
--or
arr := json_list(json(obj.get('Order')).get('sm_pack'));
arr.print;
/*Get object value from within list*/
val := json_ext.get_number(json(arr.get(2)), 'id');
DBMS_OUTPUT.PUT_LINE(VAL);
END;
/
Notice I used get_number function as your values without single quotes, otherwise, I would use get_string.
Hope that helps!

Related

Incrementing a value progressively on each item

So i have this Grafana dashboard that i'm making up using jq and different files. The problem i end up with is that when you export the json produced by Grafana, it will export it the way it sees it currently. Example:
[
{
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 22
},
"panels": []
},
{
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 43
},
"panels": []
},
{
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 17
},
"panels": []
}
]
But the problem is that the grid positions need to be properly incremented (the Y's) so that when you reload the Grafana dashboards, the panels nested under row panels get set to their proper locations. If you have a sub panel that has a gridPos.y that is lower than the row panel's gridPos.y then it will appear in a weird location.
I tried using reduce and foreach but i'm not super good with these constructs yet. For example, i tried this:
[
1 as $currentY |
foreach .[] as $item (
[];
(. + [$item * {"gridPos": {"y": ($currentY + 1)}}]);
. | last
)
]
But i can't figure out how to increment $currentY within the loop to achieve proper incrementation. The objective would be to nest a second foreach/reduce to continue setting and incrementing $currentY in all panels and sub panels.
Can you help? Thanks!
Note: I know i should use reduce when using .|last, this was just the last try. Don't point that out, i want guidance on how to increment $currentY in the current approach.
With your existing approach as such, you need to reference the y field in each $item processed and increment its value, rather than the predefined value of $currentY, i.e.
[
1 as $currentY |
foreach .[] as $item (
[];
(. + [$item * {"gridPos": {"y": ($currentY + $item.gridPos.y )}}]);
last
)
]
which again could be written as
[
1 as $currentY |
foreach .[] as $item (
[];
(. + [ $item | .gridPos.y += $currentY ]);
last
)
]
which again could be written with a simple walk expression
1 as $currentY |
walk ( if type == "object" and has("gridPos") then .gridPos.y += $currentY else . end )

extract value from JSON object using SQLite and the json_tree function

I have a table (named, patrons) that contains a column (named, json_patron_varfields) of JSON data--an array of objects that looks something like this:
[
{
"display_order": 1,
"field_content": "example 1",
"name": "Note",
"occ_num": 0,
"varfield_type_code": "x"
},
{
"display_order": 2,
"field_content": "example 2",
"name": "Note",
"occ_num": 1,
"varfield_type_code": "x"
},
{
"display_order": 3,
"field_content": "some field we do not want",
"occ_num": 0,
"varfield_type_code": "z"
}
]
What I'm trying to do is to target the objects that contain the key named varfield_type_code and the value of x which I've been able to do with the following query:
SELECT
patrons.patron_record_id,
json_extract(patrons.json_patron_varfields, json_tree.path)
FROM
patrons,
json_tree(patrons.json_patron_varfields)
WHERE
json_tree.key = 'varfield_type_code'
AND json_tree.value = 'x'
My Question is... how do I extract (or even possibly filter on) the values of the field_content keys from the objects I'm extracting?
I'm struggling with the syntax of how to do that... I was thinking it could be as simple as using json_extract(patrons.json_patron_varfields, json_tree.path."field_content") but that doesn't appear to be correct..
You can concat to build the string
json_tree.path || '.field_content'
With the structure you've given - you can also use json_each() instead of json_tree() which may simplify things.
extract:
SELECT
patrons.patron_record_id,
json_extract(value, '$.field_content')
FROM
patrons,
json_each(patrons.json_patron_varfields)
WHERE json_extract(value, '$.varfield_type_code') = 'x'
filter:
SELECT
patrons.patron_record_id,
value
FROM
patrons,
json_each(patrons.json_patron_varfields)
WHERE json_extract(value, '$.varfield_type_code') = 'x'
AND json_extract(value, '$.field_content') = 'example 2'

Faster method for creating key value pairs

I want to create a mapping from key (string) to value (string[]). I read a file:
gloveEmbeddings := make(map[string][]string)
f, _ := ioutil.ReadFile("./glove.840B.300d.txt")
The file is in the following format:
key0 val0_index0 val0_index1 val0_index2 val0_index3
key1 val1_index0 val1_index1 val1_index2 val1_index3
...
There are two separations, the new line and the space.
First I create a split of the new line:
newlineSplit := strings.Split(string(f), "\n")
Then I split each row with the space and put the first value in the resulting array as the key and the slice of the rest as the value:
for i := 0; i < len(newlineSplit); i++ {
spaceSplit := strings.Split(newlineSplit[i], " ")
gloveEmbeddings[spaceSplit[0]] = spaceSplit[1:]
}
fmt.Println(gloveEmbeddings)
The file is 5.5GB and this loop is taking more than 20 minutes. The goal is to be able to access the value fast given the key. Is there a better way to do this?
EDIT
I reading the file line by line.
gloveEmbeddings := make(map[string][]string)
f, _ := os.Open("./glove.840B.300d.txt")
scanner := bufio.NewScanner(f)
count := 0
for scanner.Scan() {
spaceSplit := strings.Split(scanner.Text(), " ")
gloveEmbeddings[spaceSplit[0]] = spaceSplit[1:]
if count % 10000 == 0 {
fmt.Println(count)
}
count++
}
But the counts stop printing at 2.19 million.
The loop actually runs fast, even the original version that uses ioutil.ReadFile. What was taking long was the fmt.Println(gloveEmbeddings) which was there only for debugging. Reading the file all at once and one line at a time take the same time, about 42-44 s on my machine.

regex replacement for whole object tree / reverse operation to `tostring`

So I have big json, where I need to take some subtree and copy it to other place, but with some properties updated (a lot of them). So for example:
{
"items": [
{ "id": 1, "other": "abc"},
{ "id": 2, "other": "def"},
{ "id": 3, "other": "ghi"}
]
}
and say, that i'd like to duplicate record having id == 2, and replace char e in other field with char x using regex. That could go (I'm sure there is a better way, but I'm beginner) something like:
jq '.items |= . + [.[]|select (.id == 2) as $orig | .id=4 | .other=($orig.other | sub("e";"x"))]'<sample.json
producing
{
"items": [
{
"id": 1,
"other": "abc"
},
{
"id": 2,
"other": "def"
},
{
"id": 3,
"other": "ghi"
},
{
"id": 4,
"other": "dxf"
}
]
}
Now that's great. But suppose, that there ins't just one other field. There are multitude of them, and over deep tree. Well I can issue multiple sub operations, but assuming, that replacement pattern is sufficiently selective, maybe we can turn the whole JSON subtree to string (trivial, tostring method) and replace all occurences using singe sub call. But how to turn that substituted string back to — is it call object? — to be able to add it back to items array?
Here's a program that might be a solution to the general problem you are describing, but if not at least illustrates how problems of this type can be solved. Note in particular that there is no explicit reference to a field named "other", and that (thanks to walk) the update function is applied to all candidate JSON objects in the input.
def update($n):
if .items | length > 0
then ((.items[0]|keys_unsorted) - ["id"]) as $keys
| if ($keys | length) == 1
then $keys[0] as $key
| (.items|map(.id) | max + 1) as $newid
| .items |= . + [.[] | select(.id == $n) as $orig | .id=$newid | .[$key]=($orig[$key] | sub("e";"x"))]
else .
end
else .
end;
walk(if type == "object" and has("items") then update(2) else . end)

Input map data to struct using Golang [duplicate]

This question already has answers here:
JSON and dealing with unexported fields
(2 answers)
Closed 10 months ago.
I want to put my map data to another map data using Golang. however it has struct type.
Here is my code.
birth := make(map[string]interface{})
birth["docType"] = "registerBirth"
birth["agencyCd"] = string(args[0])
birth["birthYmd"] = string(args[1])
birth["lsTypeNm"] = string(args[2])
birth["monthDiff"] = string(args[3])
birth["nationNm"] = string(args[4])
birth["sexNm"] = string(args[5])
birth["regType"] = string(args[9])
birth["regYmd"] = string(args[10])
I want to put this map data to another map but I want to use struct type.
cattle := make(map[string]interface{})
cattle["docType"] = "information"
cattle["birthInfo"] = struct {
birth map[string]interface{}
}{
birth,
}
but, when I get data.. It comes out like this.
{"birthInfo":{},"docType":"information"}
Here Is the example that I want.
"birthInfo": {
"birthYmd": "2018-07-25",
"cattleNo": "cow001",
"docType": "registerBirth",
"farmNo": "farm001",
"flatEartagNo": "eartag123123",
"lsTypeNm": "황소",
"monthDiff": "2018-07",
"nationNm": "austria",
"regType": "직접",
"regYmd": "20185-07-25",
"sexNm": "M"
},
"docType": "information",
...
Thanks in advance.
The problem is with this section of code
cattle["birthInfo"] = struct {
birth map[string]interface{}
}{
birth,
}
The json package can only marshal values that are exported (public / start with a capital letter).
Change the code block to this and it will work:
cattle["birthInfo"] = struct {
Birth map[string]interface{} // note: capital "Birth", exported
}{
birth,
}
Runnable example with exported field name:
https://play.golang.org/p/maTKn95AoGM

Resources