Home > Enterprise >  strip all but the first element of an object with jq
strip all but the first element of an object with jq

Time:02-18

Assume I have a json structure like:

{
  "a" : 1,
  "b" : 2,
  "c" : 3
}

I want the same structure, but with only the first element:

{
  "a" : 1
}

I don't know or care what the name of the key is. I just want the first one. (Bonus points for being able to grab an arbitrary nth one.)

How do I do this with jq?


If I did know the name, this would be easy:

% echo '{"a":1,"b":2,"c":3}' | jq '{a}'
{
  "a": 1
}

Which is a shortcut for:

% echo '{"a":1,"b":2,"c":3}' | jq '{a: .a}'
{
  "a": 1
}

Working, but terrible, solution

In trying to come up with a bunch of examples for what I've tried that didn't work, I finally came up with this thing that does work:

% echo '{"a":1,"b":2,"c":3}' | jq '{(keys|first):.[(keys|first)]}'
{
  "a": 1
}

but that cannot possibly be the best way to do this.

Notably, the "shortcut" doesn't work:

% echo '{"a":1,"b":2,"c":3}' | jq '{(keys|first)}'
jq: error: syntax error, unexpected '}', expecting ':' (Unix shell quoting issues?) at <top-level>, line 1:
{(keys|first)}
jq: 1 compile error

This also works, but is barely better, if not worse:

% echo '{"a":1,"b":2,"c":3}' | jq '(keys|first) as $i | {($i): .[$i]}'
{
  "a": 1
}

(The "shortcut" doesn't work here, either.)

WTF?

Also, if I don't use parens around the $i as the key, craziness happens that I don't understand at all:

% echo '{"a":1,"b":2,"c":3}' | jq '(keys|first) as $i | {$i: .[$i]}'
jq: error: syntax error, unexpected ':', expecting '}' (Unix shell quoting issues?) at <top-level>, line 1:
(keys|first) as $i | {$i: .[$i]}
jq: error: May need parentheses around object key expression at <top-level>, line 1:
(keys|first) as $i | {$i: .[$i]}
jq: 2 compile errors

% echo '{"a":1,"b":2,"c":3}' | jq '(keys|first) as $i | {$i}'
{
  "i": "a"
}

Other stuff that doesn't work

% echo '{"a":1,"b":2,"c":3}' | jq 'first'
jq: error (at <stdin>:1): Cannot index object with number

% echo '{"a":1,"b":2,"c":3}' | jq 'first(.)'
{
  "a": 1,
  "b": 2,
  "c": 3
}

% echo '{"a":1,"b":2,"c":3}' | jq 'first(.[])'
1

CodePudding user response:

Use to_entries, from_entries and an index of your choice.

In the single-element syntax you need to wrap it in an array

jq '[to_entries[0]] | from_entries'

Demo

In the range-syntax you need to additionally providde the to-index (which is one higher than the from-index if you want just 1 element):

jq 'to_entries[0:1] | from_entries'

Demo

Output:

{
  "a": 1
}

CodePudding user response:

You can store the value to a variable:

$ echo '{"a":2,"b":3,"c":4}' | jq '(keys|first) as $f | {($f):.[$f]}'
{
  "a": 2
}
  • Related