neilm
neilm

Reputation: 356

Sorting a JSON array by an arbitrary order using jq

Given this JSON data in the file data.json:

[
  { "id": 1, "entityType": "cat" },
  { "id": 2, "entityType": "dog" },
  { "id": 3, "entityType": "bird" },
  { "id": 4, "entityType": "cat" }
]

How would return an array sorted by some non-alphabetic arbitrary order (e.g dogs, birds and then cats)?

I've tried various permutations along the lines of:

jq --argjson order '["dog", "bird", "cat"]' '. | sort_by( index($order[], .entityType) )' data.json

but without any joy.

Upvotes: 1

Views: 71

Answers (3)

peak
peak

Reputation: 116957

If the order is defined by an array, then for efficiency it would typically be worthwhile converting the array to a dictionary along the lines suggested by @choroba:

< input.json jq --argjson order '["dog", "bird", "cat"]' '
   INDEX( $order | to_entries[]; .value ) as $dict
   | sort_by( $dict[.entityType] )
'

Upvotes: 0

choroba
choroba

Reputation: 242123

It's easier (and faster) to use an object for the order:

jq --argjson order '{"dog":0, "bird":1, "cat":2}' \
    '. | sort_by($order[.entityType])'

But if you insist:

jq --argjson order '["dog", "bird", "cat"]' \
    '. | sort_by(.entityType as $type | ($order | index($type)))'

Upvotes: 3

pmf
pmf

Reputation: 36391

If you want to keep your order argument an array, sort by turning it into an implicit boolean array of matches. Note that false will be ordered before true, so use != to "mismatch" the items.

jq --argjson order '["dog", "bird", "cat"]' 'sort_by(.entityType != $order[])'
[
  {
    "id": 2,
    "entityType": "dog"
  },
  {
    "id": 3,
    "entityType": "bird"
  },
  {
    "id": 1,
    "entityType": "cat"
  },
  {
    "id": 4,
    "entityType": "cat"
  }
]

Alternatively, provide the order as single arguments using the --args option and the $ARGS.positional array:

jq 'sort_by(.entityType != $ARGS.positional[])' data.json --args dog bird cat

Upvotes: 1

Related Questions