JSONPath cannot query if condition is a child's property of array - jsonpath

I have a json as below. I want to select list reference of item which has method is "method A". But I cannot query with operator == (with Jayway JSONPath evaluation)
$.items[*].[?(#.methods[*].name == 'method A')].reference
But when I replace operator as contains, the jsonpath works.
$.items[*].[?(#.methods[*].name contains 'method A')].reference
I don't know why operator == does not work. Could anyone help me explain the reason?
JSON:
{
"name": "List codes",
"items": [
{
"name": "Cash",
"reference": "CA",
"methods": [
{
"name": "method A",
"id": "3543"
},
{
"name": "method B",
"id": "3544"
}
]
},
{
"name": "Debt",
"reference": "DE",
"methods": [
{
"name": "method C",
"id": "3545"
},
{
"name": "method B",
"id": "3544"
}
]
},
{
"name": "Property",
"reference": "PR",
"methods": [
{
"name": "method C",
"id": "3545"
},
{
"name": "method A",
"id": "3543"
}
]
}
]
}

#.methods[*].name will yield multiple results resulting into an array. You cannot use == to compare list of values with a string.
if you need to use == operator then you have to use the index along with ||
$.items[?(#.methods[0].name == 'method A' || #.methods[1].name == 'method A')].reference

Related

How to modify each element of an array in jq

Suppose I have a JSON:
[
{
"title": "Title1",
"reference": [
"123"
]
},
{
"title": "Title2",
"reference": [
"234",
"345"
]
}
]
Id like to modify each element of the reference array so that the reference appears twice. I'd like to achieve:
[
{
"title": "Title1",
"reference": [
"123 is 123"
]
},
{
"title": "Title2",
"reference": [
"234 is 234",
"345 is 345"
]
}
]
I've tried:
jq '.[] | .reference = [("\(.reference[]) is \(.reference[])")]'
but this fails where the array has more than one item:
{
"title": "Title1",
"reference": [
"123 is 123"
]
}
{
"title": "Title2",
"reference": [
"234 is 234",
"345 is 234",
"234 is 345",
"345 is 345"
]
}
How can I modify the above jq to achieve the desired result?
Thanks in advance!
map(.reference |= map(. + " is " + .))
Will change each .reference to be .reference is .reference
[
{
"title": "Title1",
"reference": [
"123 is 123"
]
},
{
"title": "Title2",
"reference": [
"234 is 234",
"345 is 345"
]
}
]
Demo
This should work just fine:
jq '.[].reference[] |= "\(.) is \(.)"'
It replaces every item of the reference arrays with a string which contains itself two times and the word "is"

Getting a specific item in a sub array and selecting one value from it

I want to get the boardgame rank (value) from this nested array in Cosmos DB.
{
"name": "Alpha",
"statistics": {
"numberOfUserRatingVotes": 4155,
"averageRating": 7.26201,
"baysianAverageRating": 6.71377,
"ratingStandardDeviation": 1.18993,
"ratingMedian": 0,
"rankings": [
{
"id": 1,
"name": "boardgame",
"friendlyName": "Board Game Rank",
"type": "subtype",
"value": 746
},
{
"id": 4664,
"name": "wargames",
"friendlyName": "War Game Rank",
"type": "family",
"value": 140
},
{
"id": 5497,
"name": "strategygames",
"friendlyName": "Strategy Game Rank",
"type": "family",
"value": 434
}
],
"numberOfComments": 1067,
"weight": 2.3386,
"numberOfWeightVotes": 127
},
}
So I want:
{
"name": "Alpha",
"rank": 746
}
Using this query:
SELECT g.name, r
FROM Games g
JOIN r IN g.statistics.rankings
WHERE r.name = 'boardgame'
I get this (so close!):
{
"name": "Alpha",
"r": {
"id": 1,
"name": "boardgame",
"friendlyName": "Board Game Rank",
"type": "subtype",
"value": 746
}
},
But extending the query to this:
SELECT g.name, r.value as rank
FROM Games g
JOIN r IN g.statistics.rankings
WHERE r.name = 'boardgame'
I get this error:
Failed to query item for container Games:
Message: {"errors":[{"severity":"Error","location":{"start":21,"end":26},"code":"SC1001","message":"Syntax error, incorrect syntax near 'value'."}]}
ActivityId: 0a0cb394-2fc3-4a67-b54c-4d02085b6878, Microsoft.Azure.Documents.Common/2.14.0
I don't understand why this doesn't work? I don't understand what the syntax error is. I tried adding square braces but that didn't help. Can some help me understand why I get this error and also how to achieve the output I'm looking for?
This should work,
SELECT g.name, r["value"] as rank
FROM Games g
JOIN r IN g.statistics.rankings
WHERE r.name = 'boardgame'

Cannot access child value on Newtonsoft.Json.Linq.JProperty error

I have this json format I'm making an API using ASP.NET.
{
"0": {
"order_id": 11748,
"complete_date": "2021-04-19 14:48:41",
"shipping_code": "aramex.aramex",
"awbs": [
{
"aramex_id": "1314",
"order_id": "11748",
"awb_number": "46572146154",
"reference_number": "11748",
"date_added": "2021-03-04 03:46:58"
}
],
"payment": {
"method": {
"name": "الدفع عند الاستلام",
"code": "cod"
},
"invoice": [
{
"code": "sub_total",
"value": "120.8700",
"value_string": "120.8700 SAR",
"title": "الاجمالي"
},
{
"code": "shipping",
"value": "0.0000",
"value_string": "0.0000 SAR",
"title": "ارمكس"
},
{
"code": "coupon",
"value": "-13.9000",
"value_string": "-13.9000 SAR",
"title": "قسيمة التخفيض(RMP425)"
},
{
"code": "cashon_delivery_fee",
"value": "5.0000",
"value_string": "5.0000 SAR",
"title": "رسوم الدفع عند الاستلام"
},
{
"code": "tax",
"value": "18.1300",
"value_string": "18.1300 SAR",
"title": " ضريبة القيمة المضافة (15%)"
},
{
"code": "total",
"value": "130.1000",
"value_string": "130.1000 SAR",
"title": "الاجمالي النهائي"
}
]
},
"product": [
{
"id": 69,
"name": "مخلط 4 أو دو بيرفيوم للجنسين - 100 مل",
"sku": "45678643230",
"weight": "0.50000000",
"quantity": 1,
"productDiscount": "",
"images": []
}
]
}
}
How can I reach order_id? I made an object let's say its name is obj1 I tried foreach obj1 and storing into a variable obj1.order_id;
It stored null in the variable. the {"0"} is the numbering of orders starts 0-1-2 etc.
You can deserialize that json to Dictionary<string,dynamic> without creating a new class as following:
var values = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(json);
var orderId = values["0"]["order_id"].ToString();
This will give you 11748 as a result.

JQ applying function to dict but print surrounding datas

I'd like
"1": {
"id": "1",
"type": "select",
"label": "country :",
"choices": {
"1": {
"label": "Canada CAN",
"value": "",
},
"2": {
"label": "United States USA",
"value": ""
}
}
}
to produce
"1": {
"id": "1",
"type": "select",
"label": "country :",
"choices": {
"1": {
"label": "Canada",
"value": "CAN",
},
"2": {
"label": "United States",
"value": "USA"
}
}
}
By now I have a two-step solution consisting of a sed-like function
def do_extract:
if .value | test("^$") then
(.value = (.label | capture(".* (?<code>...)")).code) | .label = (.label | capture("(?<name>.*) ...$").name)
else
.
end;
and a direct access to the sub-tree []."1"."choices"|keys_unsorted as $key|map_values(do_extract) but I have to manually copy-paste the output in place of the original "choices" dict.
Is there a way to do the function but still print the surrounding datas ?
Thanks
Well to get your desired result, you could do this:
.[].choices[] |= (.label | capture("^(?<label>.*?) (?<value>[^ ]+)$"))
To do that within your function, I'd change it to this:
def do_extract:
if .value == "" then
(.label | capture("^(?<label>.*?) (?<value>[^ ]+)$"))
else
.
end;
Then use it:
.[].choices[] |= do_extract

Using jq, how can I limit values based on a key

For an input file that looks like this:
{
"employees": [
{
"number": "101",
"tags": [
{
"value": "yes",
"key": "management"
},
{
"value": "joe",
"key": "login"
},
{
"value": "joe blogs",
"key": "name"
}
]
},
{
"number": "102",
"tags": [
{
"value": "no",
"key": "management"
},
{
"value": "jane",
"key": "login"
},
{
"value": "jane doe",
"key": "name"
}
]
},
{
"number": "103",
"tags": [
{
"value": "no",
"key": "management"
},
{
"value": "john",
"key": "login"
},
{
"value": "john doe",
"key": "name"
}
]
}
]
}
... I'd like to get details for all non-management employees so that the desired output looks like this:
{
"number": "102",
"name": "jane doe",
"login": "jane"
}
{
"number": "103",
"name": "john doe",
"login": "john"
}
I can't figure out how to limit results based on a key without selecting that key (in this case "management")
The following is a slightly more succinct solution:
.employees[]
| .tags |= from_entries
| select(.tags.management == "no")
| {number, "name": .tags.name, "login": .tags.login}
Using from_entries, this worked for me:
$ jq '.employees[] | {number: .number, tags: .tags | from_entries} | select(.tags.management=="no") | {number: .number, name: .tags.name, login: .tags.login}' input
... and the output is:
{
"number": "102",
"name": "jane blogs",
"login": "jane"
}
{
"number": "103",
"name": "john doe",
"login": "john"
}
There may be a better way to achieve what I wanted, so I'll leave the question open for a while if someone wants to offer a better solution.
Here is another solution which uses from_entries
.employees[]
| {number} + (.tags | from_entries)
| if .management == "no" then {number, name, login} else empty end

Resources