使用 jq 去除对象的第一个元素以外的所有元素

strip all but the first element of an object with jq

假设我有一个 json 结构,例如:

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

我想要相同的结构,但只有第一个元素:

{
  "a" : 1
}

我不知道也不关心密钥的名称是什么。我只想要第一个(能够获得任意第 n 个奖励积分。)

如何使用 jq 执行此操作?


如果我确实知道这个名字,这就很容易了:

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

这是一个快捷方式:

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

有效但糟糕的解决方案

在尝试为我尝试过但没有用的东西想出一堆例子时,我终于想出了一个有用的东西:

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

但这不可能是最好的方法。

值得注意的是,“快捷方式”不起作用:

% 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

这也有效,但也好不了多少,甚至更糟:

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

(“快捷方式”在这里也不起作用。)

卧槽?

此外,如果我不在 $i 周围使用括号作为键,就会发生我根本不理解的疯狂情况:

% 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"
}

其他不起作用的东西

% 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

使用 to_entriesfrom_entries 和您选择的索引。

在 single-element 语法中,您需要将其包装在一个数组中

jq '[to_entries[0]] | from_entries'

Demo

在 range-syntax 中,您需要额外提供 to-index(如果您只需要 1 个元素,则比 from-index 高一个):

jq 'to_entries[0:1] | from_entries'

Demo

输出:

{
  "a": 1
}

在评论中你说

I was just hoping for something more like .[0]

如果您不喜欢其他解决方案的管道,那么使用字符串插值怎么样:

jq '{"\(keys_unsorted[0])"}'
{
  "a": 1
}

Demo

请注意,您最初的所有尝试都使用了 keys,它以 字母顺序 提供密钥。对于示例数据,这没有什么区别,但我假设您实际上是在寻找 表示顺序 中的第一个键,您需要使用 keys_unsorted。 如果我错了,那么我的答案翻译成 {"\(keys[0])"} 应该也能正常工作。

您可以使用 jq 的流解析器,如果输入对象很大,这实际上可能有意义。

# counting from 1
# e.g. 2 | nthRun(1,2,2,3; .) #=> 2,2
def nthRun(s; f):
  . as $n  
  | label $out
  | foreach s as $x (null;
      if . == null then [1, ($x|f)] 
      elif .[1] == ($x|f) then . 
      else .[0] += 1 | .[1] = ($x|f) 
      end;
      if .[0] == $n then $x 
      elif .[0] > $n then break $out 
      else empty
      end);

fromstream(1|nthRun(inputs; .[0][0]), [[null]] )

调用示例:

jq -nc --stream -f program.jq input.json

郑重声明,假设第一个键的值是原子的,您可以简单地写成:

jq -nc --stream 'fromstream(input, [[null]])'

同样的nthRun当然也可以用同样的方式访问n-thkey-value对。更一般地,它可以在不使用 --stream 选项的情况下使用,例如:

def firstKeyValue:
    fromstream(1|nthRun(tostream),[[null]]);