JSONata transpose a dynamic sized object - json

I have a json response from a REST API that looks like:
{
"Data": [
{
"Name": "MeasurementID1",
"Samples": [
{
"Time": "2021-12-31T11:15:00.000Z",
"Value": "3.280642033",
},
{
"Time": "2021-12-31T12:15:00.000Z",
"Value": "0.06151203811",
}
]
},
{
"Name": "MeasurementID2",
"Samples": [
{
"Time": "2021-12-31T11:15:00.000Z",
"Value": "53.91226196",
},
{
"Time": "2021-12-31T12:15:00.000Z",
"Value": "56.34856796",
}
]
}
]
}
I would like to transform this data for plotting in Grafana where the data is an array of table rows like
[
{ "Time": "2021-12-31T11:15:00.000Z", "MeasurementID1": "3.280642033", "MeasurementID2": "53.91226196".........."MeasurementIDxx": xxx},
{ "Time": "2021-12-31T12:15:00.000Z", "MeasurementID1": "0.06151203811", "MeasurementID2": "56.34856796".........."MeasurementIDxx": xxx}
]
I've hit a stumbling block in that the number of objects in the "Data" array is dynamic and is based on the # requested in rest api get request.
I'm stuck and don't have enough knowledge to do this transformation

If you flattened the structure a bit first, you can use the 'group-by' construct:
Data.Samples.{
"Name": %.Name,
"Time": Time,
"Value": Value
}{Time: $} ~> $each(function($v) {
$merge($v.{"Time": Time, Name: Value})
})
See https://try.jsonata.org/NXMIg7e0R

I was able to solve it by using 2 nested $reduce calls. Check it out here: https://stedi.link/egfbW8g
$reduce(Data, function($dataAcc, $dataItem) {(
$reduce($dataItem.Samples, function($samplesAcc, $sampleItem) {(
$existingItemForTime := $lookup($samplesAcc, $sampleItem.Time);
$patchForTime := {"Time": $sampleItem.Time, $dataItem.Name: $sampleItem.Value };
$merge([$samplesAcc, { $sampleItem.Time: $merge([$existingItemForTime, $patchForTime]) }])
)}, $dataAcc);
)}, {}) ~> $each(function($v) { $v })

Related

Json Extractor in JMeter

I am using JSON extractor in JMeter. Below is my Response Body. I am using the Json path expression to capture the value, which is working fine.
Apart from the above condition, I need to add one more condition.
If the "travelID" length is equal to 33, then only I need to get the BoundID.
Example : AAA-AB1234-AAABBB-2022-11-10-1111
Total length or count of the above travelID is 33, but sometime I used to get 31,32 also but I need to capture the Bound ID only when the length is 33. Is that feasible ? Please help on the same
PFB sample response body.
{
"data": {
"RenewalDetails": [
{
"ExpiryDetails": {
"duration": "xxxxx",
"destination": "XXX",
"from": "XXX",
"value": 2,
"segments": [
{
"valudeid": "xxx-xx6262-xxxyyy-1111-11-11-1111"
}
]
},
"Itemdetails": [
{
"BoundId": "xxx-1-xxx1-111111111111-1",
"isexpired": true,
"FamilyCode": "PREMIUM",
"availabilityDetails": [
{
"travelID": "AAA-AB1234-AAABBB-2022-11-10-1111",
"quota": "X",
"scale": "XXX",
"class": "X"
}
]
}
]
}
]
},
"warnings": [
{
"code": "xxxx",
"detail": "xxxxxxxx",
"title": "xxxxxxxx"
}
]
}
I don't think it's possible with JSON Extractor, I would rather suggest going for JSR223 PostProcessor and the following Groovy code:
def BoundId = new groovy.json.JsonSlurper().parse(prev.getResponseData())
.data.RenewalDetails[0].Itemdetails.find { itemDetail ->
itemDetail.availabilityDetails[0].travelID.length() == 33
}?.BoundId
vars.put('BoundId', BoundId ?: 'Not Found')
You will be able to refer extracted value as ${BoundId} later on where required.

pyjq - how to use "select" with both query and value as variables

I am writing a code in python3 where i am struggling with usage of variables with "pyjq", the code works without variables but variables are not getting parsed inside pyjq.
The documentation referred is https://github.com/doloopwhile/pyjq/blob/master/README.md#api
Please check the code given below and suggest -
My code
import json, os
import pyjq
from flask import Flask, request, jsonify
def query_records():
args = {"meta.antivirus.enabled": "true"}
for key, value in args.items():
with open('/tmp/data.txt', 'r') as f:
print (key)
print (value)
data = f.read()
records = json.loads(data)
query = ("." + key)
print (query)
#jq '.[]|select(.meta.antivirus.enabled=="true")' filename.json works,issue with variable substitution in python
match = pyjq.all('.[]|select(["$query"]==$value)', records, vars={"value": value,"query": query})
print (match)
query_records()
Content of file "/tmp/data.txt"
[
{
"name": "alpharetta",
"meta": {
"antivirus": {
"enabled": "true"
},
"limits": {
"cpu": {
"enabled": "true",
"value": "250m"
}
}
}
},
{
"meta": {
"allergens": {
"eggs": "true",
"nuts": "false",
"seafood": "false"
},
"calories": 230,
"carbohydrates": {
"dietary-fiber": "4g",
"sugars": "1g"
},
"fats": {
"saturated-fat": "0g",
"trans-fat": "1g"
}
},
"name": "sandwich-nutrition"
},
{
"meta": {
"allergens": {
"eggs": "true",
"nuts": "false",
"seafood": "true"
},
"calories": 440,
"carbohydrates": {
"dietary-fiber": "4g",
"sugars": "2g"
},
"fats": {
"saturated-fat": "0g",
"trans-fat": "1g"
}
},
"name": "random-nutrition"
}
]
Expected output(which works without variables)
{
"name": "alpharetta",
"meta": {
"antivirus": {
"enabled": "true"
},
"limits": {
"cpu": {
"enabled": "true",
"value": "250m"
}
}
}
}
Current output []
seems like some issue with variables not being passed in case of "query" , help would be appreciated.
Edit 1
It works if I hardcode "query" -
match = pyjq.all('.[]|select(.meta.antivirus.enabled==$value)', records, vars={"value": value,"query": query})
but not vice-versa
which probably narrows it down to issue with the variable "query"
JQ is not a necessity and I can use other libraries too,given that json is returned
Variables are intended to be used for values, not for jq expressions (at least not directly).
I think the easiest option here is to go for an fstring:
match = pyjq.all(f'.[]|select({query}==$value)', records, vars={"value": value})
and it probably makes sense to prepend the period inside the fstring:
match = pyjq.all(f'.[]|select(.{key}==$value)', records, vars={"value": value})

Best way to wrangle json data to remove field labels

I am looking to try make it easier to use the Google Analytics data in Google sheets.
The outputs that I receive from the api look like :
[
{
"dimensionValues": [
{
"value": "id2"
},
{
"value": "(not set)"
},
{
"value": "Android"
}
]
},
{
"dimensionValues": [
{
"value": "id1"
},
{
"value": "stream name"
},
{
"value": "iOS"
}
]
}
]
Whats the most efficient method to remove the field names to make a "flatter set of arrays" similar to:
[["id2","(not set)","Android"], ["id1","stream name","iOS"]]
It feels like there should be a quick way to do this!
You can use a double map for this one. Map the value to its dimensionValues and then map those to the array elements to get the designated output.
let array = [{"dimensionValues": [{"value": "id2"},{"value": "(not set)"},{"value": "Android"}]},{"dimensionValues": [{"value": "id1"},{"value": "stream name"},{"value": "iOS"}]}]
console.log(array.map(x => x.dimensionValues.map(y => y.value)))

jmespath :select json object element based on other (array) element in the object

I have this JSON
{
"srv_config": [{
"name": "db1",
"servers": ["srv1", "srv2"],
"prop": [{"source":"aa"},"destination":"bb"},{"source":"cc"},"destination":"cc"},]
}, {
"name": "db2",
"servers": ["srv2", "srv2"],
"prop": [{"source":"dd"},"destination":"dd"},{"source":"ee"},"destination":"ee"},]
}
]
}
I try to build a JMESPath expression to select the prop application in each object in the main array, but based on the existence of a string in the servers element.
To select all props, I can do:
*.props [*]
But how do I add condition that says "select only if srv1 is in servers list"?
You can use the contains function in order to filter based on a array containing something.
Given the query:
*[?contains(servers, `srv1`)].prop | [][]
This gives us:
[
{
"source": "aa",
"destination": "bb"
},
{
"source": "cc",
"destination": "cc"
}
]
Please mind that I am also using a bit of flattening here.
All this run towards a corrected version of you JSON:
{
"srv_config":[
{
"name":"db1",
"servers":[
"srv1",
"srv2"
],
"prop":[
{
"source":"aa",
"destination":"bb"
},
{
"source":"cc",
"destination":"cc"
}
]
},
{
"name":"db2",
"servers":[
"srv2",
"srv2"
],
"prop":[
{
"source":"dd",
"destination":"dd"
},
{
"source":"ee",
"destination":"ee"
}
]
}
]
}

How do I define this variable from a JSON response?

I am working with calling API data from weather providers and am trying to define a variable mtwnsd24 with the following code:
var mtwnsd24 = data.data.coordinates.dates.value[2];
$(".mtwnsd24").append(mtwnsd24);
}
);
The response, when run in Postman, gives the following JSON and I want to get the value "42.4".
"status": "OK",
"data": [
{
"parameter": "wind_speed_10m:kmh",
"coordinates": [
{
"lat": 40.014994,
"lon": -73.811646,
"dates": [
{
"date": "2020-01-04T05:00:00Z",
"value": 5.0
},
{
"date": "2020-01-05T05:00:00Z",
"value": 42.4
},
{
"date": "2020-01-06T05:00:00Z",
"value": 17.7
}
]
}
]
},
The definition nor any variations seem to work.
This should do the trick
data.data[0].coordinates[0].dates[1].value
Result is
42.4
Note that json array indexes are zero-based so if you want second element, you need to use index of 1