Jq: example needed for sorting deeply nested arrays

Created on 19 Feb 2015  路  6Comments  路  Source: stedolan/jq

given:

{ log: 
  { foo: "bar",
    entries: [
  {
    "s": "2015-02-19T11:02:31.869Z",
    "d": "ONE"
  },
  {
    "s": "2015-02-19T11:02:32.315Z",
    "d": "TWO"
  },
  {
    "s": "2015-02-19T11:02:32.295Z",
    "d": "THREE"
  },
  {
    "s": "2015-02-19T11:02:32.571Z",
    "d": "FOUR"
  }
]
}

how can you sort the entries array to output:

{ log: 
  { foo: "bar",
    entries: [
  {
    "s": "2015-02-19T11:02:31.869Z",
    "d": "ONE"
  },
  {
    "s": "2015-02-19T11:02:32.295Z",
    "d": "THREE"
  },
  {
    "s": "2015-02-19T11:02:32.315Z",
    "d": "TWO"
  },
  {
    "s": "2015-02-19T11:02:32.571Z",
    "d": "FOUR"
  }
]
}
support

Most helpful comment

Try:

.log.entries |= sort_by(.s)

All 6 comments

Try:

.log.entries |= sort_by(.s)

@nicowilliams :+1: Thanks

Working out how to do this from the documentation wasn't easy. Perhaps something like the following could be added to the manual or cookbook. (Is there a more idiomatic way of writing this filter?)

In-place filter and sort inner array of objects containted in outer object
Filter

.collections |= ([.[] | select([ .content[] | (contains({genre:"death"},{genre:"pop"}))]| any ) ] | sort_by(.title))

Input
{"collections":
[{"title":"collection 95"
 ,"content":
  [{"genre":"deep house"}
  ,{"genre":"progressive house"}
  ,{"genre":"dubstep"}]}
,{"title":"collection 7"
 ,"content":
  [{"genre":"Rock"}
  ,{"genre":"death rock"}
  ,{"genre":"dubstep"}
  ,{"genre":"house"}
  ]
 }
,{"title":"collection 3"
,"content":
 [{"genre":"pop"}
 ,{"genre":"progressive house"}
 ,{"genre":"dubstep"}]}

]}
Output
{
  "collections": [
    {
      "title": "collection 3",
      "content": [
        {
          "genre": "pop"
        },
        {
          "genre": "progressive house"
        },
        {
          "genre": "dubstep"
        }
      ]
    },
    {
      "title": "collection 7",
      "content": [
        {
          "genre": "Rock"
        },
        {
          "genre": "death rock"
        },
        {
          "genre": "dubstep"
        },
        {
          "genre": "house"
        }
      ]
    }
  ]
}

To invert the filter add | not like so:

.collections |= ([.[] | select([ .content[] | (contains({genre:"death"},{genre:"pop"}))]| any | not) ] | sort_by(.title))

Edit: (contains({genre:"death"}) or contains({genre:"pop"})) can be simplified to (contains({genre:"death"},{genre:"pop"}))

A filter to remove elements such as:
.collections |= ([.[] | select([ .content[] | (contains({genre:"pop"}))]|any|not)]|sort_by(.title))

Could be written as:

.collections |= (. - map(select(.content[] | (contains({genre:"pop"})))) | sort_by(.title))

But I think the former is easier to comprehend and it's also more flexible as you can easily reverse the logic by removing the | not clause.
However, neither are easy to come to from the examples in the manual.

Be careful when using contains with strings. {"genre": "pop"} will happily consider itself contained in {"genre": "tasty poptarts"}, to the dismay of those hoping to do something useful with that function. In this case, unless I'm missing anything, you could have just selected .genre == "pop"; in other cases the solution is to use index.

I can't envision an actual use-case for the actual behaviour of contains, and I'd like to have a discussion on having it fixed or removed. Probably not on this issue number, though.

@SamHasler suggested:

Perhaps something like the following could be added to the manual or cookbook.

A closely related "Q:" has been added to the General Questions section of the FAQ:

_Q:_ How can I sort an inner array of an object? How can I sort all the arrays in a JSON entity?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kelchy picture kelchy  路  4Comments

ve3ied picture ve3ied  路  4Comments

geoffeg picture geoffeg  路  3Comments

neowulf picture neowulf  路  3Comments

mcandre picture mcandre  路  3Comments