Roland Weisleder
Roland Weisleder

Reputation: 10511

Sort descending by multiple keys in jq

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

Answers (2)

Stanimir
Stanimir

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

user3899165
user3899165

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

Related Questions