I have the following json format. It's basically a representation of the calendar:
{"month1": {"day1":{...}, "day2": {...}}, "month2": {...}}
I'd like to sort it such that both the months and the days will be in numeric order. The below input is the output of jq -S
, but as you see it's sorted like: 1,10,2, and I'd like to sort it like 1,2,10. How can I do that with jq?
Input:
{
"1":{"1":{"foo":"bar"},"10":{"foo":"bar"},"2":{"foo":"bar"}},
"10":{"1":{"foo":"bar"},"10":{"foo":"bar"},"2":{"foo":"bar"}},
"2":{"1":{"foo":"bar"},"10":{"foo":"bar"},"2":{"foo":"bar"}}
}
Expected output:
{
"1":{"1":{"foo":"bar"},"2":{"foo":"bar"},"10":{"foo":"bar"}},
"2":{"1":{"foo":"bar"},"2":{"foo":"bar"},"10":{"foo":"bar"}},
"10":{"1":{"foo":"bar"},"2":{"foo":"bar"},"10":{"foo":"bar"}}
}
update:
I want to have this sorting for 2 reasons:
For all the downvoters: jq -S
wasn't invented by me and it does sort the keys of an object. Many use jq as a json prettifier/formatter/identer, so I think this is a legitimate use-case. You don't have to sort your json objects, that's fine, but why down-voting?
While the encoding of a JSON object inherently reveals some ordering of its items, JSON objects actually don't convey the notion of an order (only JSON arrays do). So, forcefully inducing a specific order onto its items is ephemeral at best. It may hold for the document's current representation, but any subsequent processor could very well just disregard this configuration, and break this order without reason, without giving any notice, and, most importantly, without violating the JSON specs. Therefore, relying on a specific order apparent in a given encoding (the actual representation as a stream of characters) is a computational bug, and should therefore be discouraged.
That said, using jq
, you can turn the items of an object into an array of key-value pairs using to_entries
, sort that array by the numeric representation of each .key
using sort_by
and to_number
, and then re-compose the object based on that array using from_entries
, which jq
will perform in the order of the array. Finally, apply this function composition to both the root node .
and its children .[]
.
Again, note that this side-effect is just the actual behavior of jqlang/jq (but not of itchyny/gojq, for example), and is nowhere guaranteed to stay that way. However, the current and several latest versions of jqlang/jq (at least until v1.7) seem to be implemented this way.
(.[], .) |= (to_entries | sort_by(.key | tonumber) | from_entries)
{
"1": {
"1": {
"foo": "bar"
},
"2": {
"foo": "bar"
},
"10": {
"foo": "bar"
}
},
"2": {
"1": {
"foo": "bar"
},
"2": {
"foo": "bar"
},
"10": {
"foo": "bar"
}
},
"10": {
"1": {
"foo": "bar"
},
"2": {
"foo": "bar"
},
"10": {
"foo": "bar"
}
}
}