Trouble Parsing Array vs Non-Array JSON with JSONPath - json

I have JSON that looks like the below. I'm trying to use JSONPath to grab the __ content __ value where the SKU is "8A-OK9F-9LI8" AND the Component.Type == 'Principal'. Right now, I am playing around with this JSON Path Expression Tester.
This JSONPath expression grabs all of the component information I need:
$.Order..Fulfillment[?(#.SKU=='8A-OK9F-9LI8')]..Component
But filtering further such as $.Order..Fulfillment[?(#.SKU=='8A-OK9F-9LI8')]..Component[?(#.Type=='Principal')] grabs only one (I believe the Array one) of the two Component elements I need. I suspect this is because one is an Array and one is a single JSON element. Is it possible to grab this with one command or do I have to combine several commands (one for the Array and one for the single JSON element)? If so, how can I grab the other Component information that I am not currently getting with:
$.Order..Fulfillment[?(#.SKU=='8A-OK9F-9LI8')]..Component[?(#.Type=='Principal')]?
Again, my goal is to grab the "__ content__" value and filter by a specific SKU and where the Component.Type == 'Principal'. Something like:
$.Order..Fulfillment[?(#.SKU=='8A-OK9F-9LI8')]..Component[?(#.Type=='Principal')]..Amount..__content__
I'm expecting to get back ["8.49", "8.49"]
Here is the JSON I am testing with:
{
"SettlementData": {},
"Order": [
{
"OrderID": "XXX",
"Fulfillment": {
"Item": {
"SKU": "8A-OK9F-9LI8",
"Quantity": "1",
"ItemPrice": {
"Component": [
{
"Type": "Principal",
"Amount": {
"__content__": "8.49",
"currency": "USD"
}
},
{
"Type": "Tax",
"Amount": {
"__content__": "0.74",
"currency": "USD"
}
}
]
}
}
}
},
{
"OrderID": "XXX",
"Fulfillment": {
"Item": {
"SKU": "8A-OK9F-9LI8",
"Quantity": "1",
"ItemPrice": {
"Component": {
"Type": "Principal",
"Amount": {
"__content__": "8.49",
"currency": "USD"
}
}
}
}
}
}
]
}

I was able to solve this in two passes. In this example, #{sku} is a Ruby interpolated string that contains the SKU I am passing in:
$.Order..Fulfillment[?(#.SKU=='#{sku}')]..ItemPrice..[?(#.Type=='Principal')].Amount.__content__
$.Order..Fulfillment..Item[?(#.SKU=='#{sku}')]..ItemPrice..[?(#.Type=='Principal')].Amount.__content__
Using a Ruby gem "jsonpath", I was able to get the amounts I needed like this:
amount = JsonPath.on(settlement, "$.Order..Fulfillment[?(#.SKU=='#{sku}')]..ItemPrice..[?(#.Type=='Principal')].Amount.__content__")
.map(&:to_f).inject(:+)
amount2 = JsonPath.on(settlement, "$.Order..Fulfillment..Item[?(#.SKU=='#{sku}')]..ItemPrice..[?(#.Type=='Principal')].Amount.__content__")
.map(&:to_f).inject(:+)

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.

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"
}
]
}
]
}

Find specific value in a large json file

I've a simple json array similar to the below. I'd like to find the record that contain a matching value, say for example name == jack.
{
"data": [
{
"Record": {
"attributes": {
"name": "Jack",
"age": "38",
"description": "1234",
}
}
}
]
}
Below python code works but it is very slow. Is there any way to get the results quicker?
with open('records.json') as f:
input_dict = json.load(f)
input_var = input_dict["data"]
for i in input_var:
if i["Record"]["attributes"]["name"] == "Jack":
print(i["Record"]["attributes"])
break

Build a JSON document from a sqlite table

I've been looking at the JSON1 extension for SQLite databases as a potential tool to use to compose a JSON document from a table-valued result.
I have a result set coming out of my SQLite database that resembles something like this:
CLASS|INSTANCE|PROPERTY|FROM|TO
ABC|12345|COLOR|RED|
ABC|12345|COLOR|GREEN|
ABC|12345|WEIGHT|1|10
ABC|56789|COLOR|BLUE|
ABC|56789|HEIGHT|4.5|6.2
DEF|2345|NAME|YOMOMMA|
I've been trying to make a JSON document based off of this data to look like:
{
"ABC": {
"12345": {
"COLOR": [
{ "from": "RED", "to": "" },
{ "from": "GREEN", "to": ""}
],
"WEIGHT": [
{ "from": "1", "to": "10" }
]
},
"56789": {
"COLOR": [
{ "from": "BLUE", "to": "" }
],
"HEIGHT": [
{ "from": "4.5", "to": "6.2" }
]
}
},
"DEF": {
"2345": {
"NAME": [
{ "from": "YOMOMMA", "to": "" }
]
}
}
}
I've been trying to get the JSON1 functions to help me out with this, but it seems they don't really support a multilayered JSON format (or at least, not that I've been able to see). If I wrap my result set in a group by query, I can get the properties to nicely turn into a JSON array, but when I try to wrap that into the next level, all the JSON gets escaped (would have been nice if there was a json_raw() function, but I'd imagine implementing it would be challenging).
Can this be done (relatively) easily using SQLite/ JSON1? Is there a different/ better way to create my document than using JSON1, or am I just going to have to write code for this?

JSONPath expression to look inside different keys

I have a JSON returned by a RESTful API:
{
"0": {
"id": "1484763",
"name": "Name",
"values": {
"0": {
"value": "Peter"
}
}
},
"1": {
"id": "2584763",
"name": "phone",
"values": {
"0": {
"value": "45456456"
}
}
}
}
How do I write a JSONPath that extracts a phone number value? (so in this case, "45456456"). What makes the problem harder, phone number object is not always inside "1" key.
Try this JsonPath which results in phone number 45456456
$..[?(#.name = 'phone')].values.0.value
Basically, you have to apply a filter ?() where name == 'phone' and then use normal json path.
Try the expression in this link
JsonPath expression syntax can be found here.