get the first (or n'th) element in a jq json parsing

JsonJq

Json Problem Overview


I can get the 1st element in a json inside []

$ echo '[{"a":"x", "b":true}, {"a":"XML", "b":false}]' | jq '.[1]'
{
  "a": "XML",
  "b": false
}

But if the json is already disassembled (for instance, after filtering entries using 'select'), how can I choose a single entry and avoid the error seen here?

$ echo '[{"a":"x", "b":true}, {"a":"x", "b":false},{"a":"XML", "b":false}]' | jq '.[] | select( .a == "x")'
{
  "a": "x",
  "b": true
}
{
  "a": "x",
  "b": false
}
$ echo '[{"a":"x", "b":true}, {"a":"x", "b":false},{"a":"XML", "b":false}]' | jq '.[] | select( .a == "x") | .[1]'
jq: error (at <stdin>:1): Cannot index object with number

Json Solutions


Solution 1 - Json

You can wrap the results from select in an array:

jq '[.[]|select(.a=="x")][0]' your.json

Output:

{
  "a": "x",
  "b": false
}

Solution 2 - Json

jq also provides first/0, last/0, nth/1 so in this case the filter

  ( map(select(.a == "x")) | first  )
, ( map(select(.a == "x")) | last   ) 
, ( map(select(.a == "x")) | nth(1) )

produces

{
  "a": "x",
  "b": true
}
{
  "a": "x",
  "b": false
}
{
  "a": "x",
  "b": false
}

Additional streaming forms 'first/1', 'last/1' and 'nth/2' are also available so with this data

  ( first(.[]  | select(.a == "x")) )   
, ( last(.[]   | select(.a == "x")) )
, ( nth(1; .[] | select(.a == "x")) )

produces

{
  "a": "x",
  "b": true
}
{
  "a": "x",
  "b": false
}
{
  "a": "x",
  "b": false
}

Solution 3 - Json

Many of the previous answers work by avoiding to create a stream of objects in the first place. But what if you are starting with a stream of objects—for example JSON-formatted application logs? If your input file (or stream) has multiple objects in it, all you need to do to choose a single entry from a stream of independent objects is to use the --slurp option (or -s for the short form):

> o --slurp/-s: > > Instead of running the filter for each JSON object in the input, read > the entire input stream into a large array and run the filter just once.

Then you can just index into the array. For example, to get second item (with index 1):

jq --slurp '.[1]'

Putting this together with your original question, where you want to select that item from a stream:

echo '{"a":"x", "b":true} {"a":"XML", "b":false}' | jq --slurp '.[1]'

which results in this output:

{
  "a": "XML",
  "b": false
}

Solution 4 - Json

use map

cat raw.json|jq -r -c 'map(select(.a=="x"))|.[1]'

map recivce a filter to filter an array.

this command

cat raw.json|jq -r -c 'map(select(.a=="x"))'

give the middle result

[{"a":"x","b":true},{"a":"x","b":false}]

.[1] take the first element

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDemian GlaitView Question on Stackoverflow
Solution 1 - Jsonhek2mglView Answer on Stackoverflow
Solution 2 - Jsonjq170727View Answer on Stackoverflow
Solution 3 - JsonjbylerView Answer on Stackoverflow
Solution 4 - JsontinkView Answer on Stackoverflow