Reputation: 10511
I have the following array:
[{
"name": "Object 1",
"prop1": 5,
"prop2": 2
}, {
"name": "Object 2",
"prop1": 6,
"prop2": 4
}, {
"name": "Object 3",
"prop1": 5,
"prop2": 3
}]
I want to sort this array analogous to this SQL ORDER BY prop1 DESC, prop2 ASC
so I have this result:
[{
"name": "Object 2",
"prop1": 6,
"prop2": 4
}, {
"name": "Object 1",
"prop1": 5,
"prop2": 2
}, {
"name": "Object 3",
"prop1": 5,
"prop2": 3
}]
How can I sort an array a) descending by a key and b) by multiple keys?
Version: jq 1.5
Upvotes: 35
Views: 28178
Reputation: 196
One may use the reverse
(jq 1.5 Manual) function like:
$ jq -n '["pro", "leo", "column", "ablast"] | sort | reverse'
[
"pro",
"leo",
"column",
"ablast"
]
So your specific example may become:
$ jq -n '[{...}, {...}, {...}, {...}] | sort_by(.prop2) | reverse | sort_by(.prop1) | reverse'
[
{
"name": "Object 2",
"prop1": 6,
"prop2": 4
},
{
"name": "Object 1",
"prop1": 5,
"prop2": 2
},
{
"name": "Object 3",
"prop1": 5,
"prop2": 3
}
]
SQL ORDER BY prop1 DESC, prop2 ASC
→ jq | sort_by(.prop2) | reverse | sort_by(.prop1) | reverse
– Note, the sorting is specified with properties in the reverse order, and reverse
is used twice.
Given prop1
and prop2
are numeric, the accepted answer (sort_by(-.prop1, .prop2)
) is much simpler/better.
Upvotes: 12
Reputation:
In jq, arrays sort by the sorting of the elements they contain, in order. That is:
$ jq -n '[1, 2] < [1, 3], [1, 2] < [2, 1]'
true
true
The sort_by
filter sorts an array, taking an expression as argument that will be evaluated for each member of the array. For example, if you wanted to sort a list of words by length:
$ jq -n '["prop", "leo", "column", "blast"] | sort_by(length)'
[
"leo",
"prop",
"blast",
"column"
]
If the expression given to sort_by
as argument returns more than one value, the return values will be implicitly wrapped in an array, which will be subject to the array sorting rules referred to above. For example, if you wanted to sort a list of words by length, and then alphabetically:
$ jq -n '["pro", "leo", "column", "ablast"] | sort_by(length, .)'
[
"leo",
"pro",
"ablast",
"column"
]
Knowing this, and taking into account that the values in your example are numeric, you can just do the following:
$ jq 'sort_by(-.prop1, .prop2)'
Upvotes: 40