Use jq to sort keys in json using one of the properties
I need to sort following JSON file by keys with natural order but keys that a listed in the 'required` section should go first, how to do that?
Following command sorts only by keys putting them in natural order:
jq --sort-keys . /tmp/source.json > ./tmp/target.json
{
"Request": {
"properties": {
"capacity": {
"$ref": "SubscriptionCapacity"
},
"metadata": {
"$ref": "MeterDefinitionsAndPolicy"
},
"data": {
"type": "string"
},
"avs": {
"pattern": "standard:v2",
"type": "string"
}
},
"required": [
"data",
"avs"
],
"type": "object"
}
}
Expected output should be like:
{
"Request": {
"properties": {
"avs": {
"$ref": "Pricing"
},
"data": {
"type": "string"
}
"capacity": {
"$ref": "SubscriptionCapacity"
},
"metadata": {
"$ref": "MeterDefinitionsAndPolicy"
}
},
"required": [
"data",
"avs"
],
"type": "object"
}
}
Solution 1:
Here's a straightforward and fairly efficient approach that takes advantage of the fact that keys
produces the key names as a sorted array:
. as $in
| .Request
| (.required|sort) as $required
| (.properties|keys) as $all
| ($all - $required) as $optional
| .properties as $p
| $in
| .Request.properties = reduce ($required[], $optional[]) as $key ({}; . + {($key): $p[$key]} )
Note that gojq, the Go implementation of jq, does support keys
but does not in general respect user-specified ordering of keys within objects.
Solution 2:
You can do something along the lines of
.Request.required as $req
| .Request.properties |= (
to_entries
| sort_by(.key)
| group_by(IN(.key; $req[]) | not)
| map(from_entries)
| add
)
{
"Request": {
"properties": {
"avs": {
"pattern": "standard:v2",
"type": "string"
},
"data": {
"type": "string"
},
"capacity": {
"$ref": "SubscriptionCapacity"
},
"metadata": {
"$ref": "MeterDefinitionsAndPolicy"
}
},
"required": [
"data",
"avs"
],
"type": "object"
}
}
Demo
but you are not guaranteed that after any follow-up processing the order will stay the same as objects typically do not have an order, arrays do.