Approach:
Get a list of masters and extract their types. This ordered set tells us in what order to process the rest of the data.
( .[] | select(.role == "master").type )For the given data, this is the set
"A","C","B".Loop over this set and extract the elements that have that type and that have the role of master, followed by the ones that have that type and that does not have the role of master.
Looping with
$typeas the loop variable is done with( .[] | select(.role == "master").type ) as $typeWe extract the masters followed by the non-masters:
( .[] | select(.type == $type and .role == "master" ) ), ( .[] | select(.type == $type and .role != "master" ) )Put everything into an array. This involves putting
[and]around everything.
We end up with
[
( .[] | select(.role == "master").type ) as $type |
( .[] | select(.type == $type and .role == "master" ) ),
( .[] | select(.type == $type and .role != "master" ) )
]
There's really no sorting going on here. We're simply extracting data in an orderly fashion and creating a new array out of this.
Alternative approach: Extracting the whole master elements out of the array first, not just their types:
[
( .[] | select(.role == "master") ) as $master |
$master,
( .[] | select(.type == $master.type and .role != "master" ) )
]
Another approach: Using grouping of the initial array to separate the master elements form the others first. This assumes that there are only elements with either master roles or no role at all.
group_by(.role) |
[
.[1][] as $master |
$master,
( .[0][] | select(.type == $master.type)) )
]
The first line here first groups the original array into two parts, .[0] has the elements with no rolerole, and .[1] has the ones with a rolerole.
We then loop over the master elements in .[1] and select the elements out of .[0] that corresponds to the current $master's type.
An array is created with each master element followed by the non-master elements in turn.