Cleaner way of iterating nested JSON in ruby - json

I was wondering if there is any 'cleaner' way of looping through nested JSON in ruby?
This is my JSON object:
{
"data": [
{
"file": "test/test_project_js/jquery.js",
"results": [
{
"vulnerabilities": [
{
"severity": "high"
},
{
"severity": "medium"
},
{
"severity": "none"
},
{
"severity": "high"
}
]
}
]
},
{
"file": "test/test_project_js/jquery.js",
"results": [
{
"vulnerabilities": [
{
"severity": "none"
},
{
"severity": "none"
},
{
"severity": "none"
},
{
"severity": "high"
}
]
}
]
}
]
}
I want to extract severity under each vulnerability present inside each results[] which is under data[]
Current code approach is
severity_arr = raw['data'].each do |data|
data['results'].each do |result|
result['vulnerabilities'].map {|vulnerability| vulnerability['severity']}
end
end

You can use flat_map and dig:
data[:data].flat_map { |datum| datum.dig(:results, 0, :vulnerabilities) }
# [{:severity=>"high"}, {:severity=>"medium"}, {:severity=>"none"}, {:severity=>"high"}, {:severity=>"none"}, {:severity=>"none"}, {:severity=>"none"}, {:severity=>"high"}]
What's maybe not convenient, is that data.results holds an array with a single hash. Maybe a hash is enough for that.

Related

how can i insert a Netsuite inventory adjustment with lot numbered items with suitetalk?

I don't know how to configure the inventory detail in the JSON
I'm trying to POST at https://<>.suitetalk.api.netsuite.com/services/rest/record/v1/inventoryAdjustment
this JSON
{
"account": 4738,
"trandate":"2022-11-14",
"subsidiary":3,
"inventory":
{
"items":
[
{
"item": 9908,
"location":25,
"adjustQtyBy": 100,
"memo":"m-203174 p-21992 c-TM/55 #2"
,
"inventoryDetail":
{
"inventoryAssignment":
[
{
"receiptInventoryNumber": 2002111,
"quantity": 100
}
]
}
}
]
}
}
but i'm receiving this error:
{
"type": "https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1",
"title": "Bad Request",
"status": 400,
"o:errorDetails": [
{
"detail": "Error while accessing a resource. You still need to reconfigure the inventory detail record after changing the quantity.",
"o:errorPath": "inventory.items[0]",
"o:errorCode": "USER_ERROR"
}
]
}
i got this second error after changing inventorydetail section:
{
"type": "https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1",
"title": "Bad Request",
"status": 400,
"o:errorDetails": [
{
"detail": "Invalid content in the request body.",
"o:errorCode": "INVALID_CONTENT"
}
]
}
Now it works
{
"account": 4737,
"trandate":"2022-11-14",
"subsidiary":3,
"inventory":
{
"items":
[
{
"item": 9908,
"location":25,
"adjustQtyBy": 100,
"memo":"P$203174$21992$TM/55$2"
,
"inventoryDetail":
{
"inventoryAssignment":
{
"items":
[
{
"receiptInventoryNumber": 2002111,
"quantity": 100,
"expirationDate":"2022-11-30"
}
]
}
}
}
]
}
}

Fetching the array name when traversing array items in JSONata

I need to fetch the name of the array while traversing the child array items.
for example, if my input looks like
{"title": [
{
"value": "18724-100",
"locale": "en-GB"
},
{
"value": "18724-5",
"locale": "en-GB"
},
{
"value": "18724-99",
"locale": "fr-FR"
}
]}
I need output as
{
"data": [
{
"locale": "en-GB",
"metadata": [
{
"key": "title",
"value": "18724-100"
},
{
"key": "title",
"value": "18724-5"
}
]
},
{
"locale": "fr-FR",
"metadata": {
"key": "title",
"value": "18724-99"
}
}
]
}
I tried following spec in JSONata
{
"data": title{locale: value[]} ~> $each(function($v, $k) {
{
"locale": $k,
"metadata": $v.{"key": ???,"value": $}
}
})
}
Please help me to fill "???" so that I can get the array name
Assuming that the input object will always have a single root-level key you can write your expression like this:
{
"data": title{locale: value[]} ~> $each(function($v, $k) {
{
"locale": $k,
"metadata": $v.{"key": $keys($$)[0],"value": $}
}
})
}
$keys returns an array containing keys in the object. $keys($$) will return all keys in root-level of this array (in this case: "title").
Note that for a following input object:
{"title": [
{
"value": "18724-100",
"locale": "en-GB"
},
{
"value": "18724-5",
"locale": "en-GB"
},
{
"value": "18724-99",
"locale": "fr-FR"
}
],
"foo": 123
}
$keys($$) would return an array of two elements (["title", "foo"]).

Read Array Value Using Dataweave in Mule

I am trying to use dataweave in Mule to read specific data values from an incoming payload. My sample payload looks like below:
{
"source": [
{
"uri": "entities/1R6xV",
"createdBy": "API_USER",
"createdTime": 1562504739146,
"attributes": {
"label": "000000000002659654",
"value": {
"Name": [
{
}
],
"Id": [
{
}
],
"Number": [
{
"type": "config/Types/Number/attributes/Number",
"ov": true,
"value": "000000000002659654",
"uri": "entities/1R6xV/attributes/Num/1ZtyT/Number/60pvN6"
}
]
}
}
}
]
}
If I need to read the "label", I can achieve that by
label: payload.source.attributes.label
Similarly, how can I read the "value" under attributes > Number. It doesn't work by:
Value: payload.source.attributes.Number.value
I am new to Dataweave. Please advise.
The problem is that the dot selector (.) works on object and on array of objects. When it is applied to an array it will apply the dot selector to all the elements of the array that are of type object and return that result.
Lets go part by part
payload.source
Returns
[
{
"uri": "entities/1R6xV",
"createdBy": "API_USER",
"createdTime": 1562504739146,
"attributes": {
"label": "000000000002659654",
"value": {
"Name": [
{
}
],
"Id": [
{
}
],
"Number": [
{
"type": "config/Types/Number/attributes/Number",
"ov": true,
"value": "000000000002659654",
"uri": "entities/1R6xV/attributes/Num/1ZtyT/Number/60pvN6"
}
]
}
}
}
]
So far so good as payload is an Object it returns the value of source that is an array
payload.source.attributes
Returns
[
{
"label": "000000000002659654",
"value": {
"Name": [
{
}
],
"Id": [
{
}
],
"Number": [
{
"type": "config/Types/Number/attributes/Number",
"ov": true,
"value": "000000000002659654",
"uri": "entities/1R6xV/attributes/Num/1ZtyT/Number/60pvN6"
}
]
}
}
]
Works ok because the result of payload.source was ended an Array of object so it will do that selection over those objects.
Now when you execute
payload.source.attributes.value.Number
It returns
[
[
{
"type": "config/Types/Number/attributes/Number",
"ov": true,
"value": "000000000002659654",
"uri": "entities/1R6xV/attributes/Num/1ZtyT/Number/60pvN6"
}
]
]
That is an array of arrays and here is where it is broken.
My Solution
You have two alternatives here
Use flatten function
flatten(payload.source.attributes.value.Number).value
Use descendant selector
payload.source.attributes.value.Number..value
Since Number is an array, you need to specify the index you want. In this case, the zeroth element:
Value: payload.source[0].attributes.value.Number[0].value
If you have multiple numbers, it would look something like this:
%dw 1.0
%output application/json
---
values: payload.source[0].attributes.value.Number map {
value: $.value
}

How to send carousel through API.AI?

My bot wants to send a carousel to Google Assistant through API.AI. My understanding is, I need to enclose it inside data -> google, such as:
{
"data": {
"google": {
"expectUserResponse": true,
"isSsml": false,
"expectedInputs": [
{
"inputPrompt": {
"richInitialPrompt": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Hello World"
}
}
]
}
},
"possibleIntents": [
{
"intent": "actions.intent.OPTION",
"inputValueData": {
"#type": "type.googleapis.com/google.actions.v2.OptionValueSpec",
"carouselSelect": {
"items": [
{
"optionInfo": {"key": "FOO", "synonyms": ["foo"]},
"title": "Foo",
"image": {"url": "http://example.com/", "accessibilityText": "Foo"}
},
{
"optionInfo": {"key": "BAR", "synonyms": ["bar"]},
"title": "Bar",
"image": {"url": "http://example.com/", "accessibilityText": "Bar"}
}
]
}
}
}
]
}
]
}
}
}
But it doesn't work. What is the proper format?
If you are testing this through the Simulator, there should have been a validation error that appeared that would give you at least a little guidance about what is missing. If you didn't even get that, there may be a problem with the other parts besides the data.google object such that api.ai had problems with it.
There are a number of things that, at a glance, could be the problem. You can't just stick a conversation webhook response in the api.ai response. See https://developers.google.com/actions/apiai/webhook#response for the documentation, but here are a few things that I see that could be issues
The expectedInputs property shouldn't be there.
Your data.google.expectedInputs.possibleIntents property should be at data.google.systemIntent
You still need to provide the api.ai fields, such as a basic speech property
The data.google.expectedInputs.inputPrompt.richInitialPrompt would be at data.google.richResponse
Here is some JSON that works for me:
{
"speech": "Hello",
"contextOut": [
{
"name": "_actions_on_google_",
"lifespan": 100,
"parameters": {}
}
],
"data": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Hello"
}
}
],
"suggestions": []
},
"systemIntent": {
"intent": "actions.intent.OPTION",
"data": {
"#type": "type.googleapis.com/google.actions.v2.OptionValueSpec",
"carouselSelect": {
"items": [
{
"title": "Foo",
"image": {
"url": "http://example.com/foo.jpg",
"accessibilityText": "Foo title"
},
"optionInfo": {
"key": "foo-key",
"synonyms": [
"foo-alt-1",
"foo-alt-2"
]
}
},
{
"title": "Bar",
"image": {
"url": "http://example.com/bar.jpg",
"accessibilityText": "Bar title"
},
"optionInfo": {
"key": "bar-key",
"synonyms": [
"bar-alt-1",
"bar-alt-2"
]
}
}
]
}
}
}
}
}
}

Elastic search 2.1 query to get only a element from an array

I have below mapping, I want to access a property of imageMap instead of all collection.
"imageMap": {
"properties": {
"item1": {
"type": "long"
},
"item2": {
"type": "string"
},
"item3": {
"type": "string"
}
}
}
Below is the sample data
imageMap": [
{
"item1": 20893,
"item2": "ImageThumbnail_100_By_44",
"item3": "/9j/4AAQSkZJRg"
},
{
"item1": 20893,
"item2": "ImageThumbnail_400_By_244",
"item3": "/9j/4AAQSkZJRgABAQEAYABgAAD/2w"
}
]
Below is my Query that is not working. Any help is appreciated. Thank you in advance.
Updated:
{
"_source": {
"include": [
"imageMap"
]
},
"query": {
"bool": {
"must": [
{
"term": {
"imageMap.item1": {
"value": 20893
}
},
"term": {
"imageMap.item2": {
"value": "imagethumbnail_100_by_44"
}
}
}
]
}
}
}
Expected Result is below only single element of imageMap, but i am getting array :
"_source": {
"imageMap": [
{
"item2": "ImageThumbnail_100_By_44",
"item1": 20893,
"item3": "/9j/4AAQSkZJRgABAQ"
}
]
}
If you only wan to get a single element from the imageMap array, you need to map imageMap as a nested object like this:
"imageMap": {
"type": "nested", <--- add this
"properties": {
"item1": {
"type": "long"
},
"item2": {
"type": "string"
},
"item3": {
"type": "string"
}
}
}
Then you need to wipe your index and re-build it from scratch with this new mapping.
In the end, you'll be able to retrieve only a specific element using a nested inner_hits query:
{
"_source": false,
"query" : {
"nested" : {
"path" : "imageMap",
"query" : {
"match" : {"imageMap.item2" : "ImageThumbnail_100_By_44"}
},
"inner_hits" : {}
}
}
}
Your query is not working because you are using term query which does not do any analysis on your search string. Since you have not specified any analyzer in mapping ImageThumbnail_100_By_44 is stored as imagethumbnail_100_by_44 because it is analyzed by standard analyzer
Depending on your requirement you could either map your item2 as "index : not_analyzed" and your query will work fine or you could use match query which will do analysis.
{
"_source": {
"include": [
"imageMap"
]
},
"query": {
"bool": {
"must": [
{
"match": {
"imageMap.item2": {
"query": "ImageThumbnail_100_By_44"
}
}
}
]
}
}
}
Please go through this document to have better understanding of analysis process