首先,简单的部分:你需要使用
.newList."243"
(带双引号)来访问
"243"
的详细信息。jq将
.243
解释为数字而不是字符串,而对象键都是字符串。
但正如你所说,事先不知道键名,所以我们不能使用特定的键。没关系,如果需要,有办法获取它们。而且无论如何,你最初的问题只要求名称和创建日期,所以我们可以忽略数字键。
简单版本
为了丢弃键名,我们可以使用
values
过滤器,然后可以使用
map
将其他过滤器应用于值。因此,我们的解决方案将类似于
cat input.json | jq ' .newList | values | map(some_filter) '
。
什么是
some_filter
?嗯,它可以是任何我们想要的东西,只要它接受正确类型的对象,并输出我们所需的结果。我曾尝试将这些内容写成一行代码,但我发现如果使用def关键字来定义自己的过滤器(就像在其他语言中定义辅助函数一样),那么使用jq会更容易理解。
我的建议解决方案:
cat input.json | jq `
def details_to_string:
. | "Details: \(id), \(.name), \(.create.date)";
.newList | values | map(details_to_string)
`
这是如何工作的?
在我们开始处理输入之前,我们定义了一个名为'details_to_string'的新过滤器。它接受一个具有'id'字段和'.create.date'字段的对象,并使用字符串插值返回一个字符串。(我不确定您想要什么输出格式,但格式化的字符串是一个简单的例子)。请注意'def'行末尾的冒号以及实际过滤器定义末尾的分号。
实际处理从最后一行开始。这是将输入文件中的JSON对象输入程序的地方。
首先,对象经过一个'newList'过滤器,结果是newList对象(其中
{ "243": X, "244": Y }
,其中
X
和
Y
是较小的JSON对象)。
接下来,该对象经过'values'过滤器,结果是值的数组(
[ X, Y]
,其中
X
和
Y
是上述相同的较小JSON对象)。
最后,该数组通过'map(details_to_string)'。Map接受一个数组,并通过将其通过'details_to_string'过滤器来更改数组中的每个项。因此,它接受一个类似于
[X_details_object, Y_details_object]
的数组,并输出一个类似于
[X_string, Y_string]
的数组。
输出是什么?
[
"Details: 243, test, 2017-08-31 13:57:29",
"Details: 244, test, 2017-08-31 13:57:29"
]
如果你只想要单独的字符串(没有方括号,没有逗号),那么你可以在最后将数组拆开。(
.newList | values | map(details_to_string) | .[]
)。如果你还将'jq'改为'jq -r',那么你也会去掉引号。
如果你只想要列表中的第一项,那么你可以用
.[0]
提取出来:
.newList | values | .[0] | details_to_string
(注意我们现在不再需要数组,所以不再需要
map
)。
更有趣的版本
在上面的评论中,你问到如何捕获并包含键"243"和"244",并且你提到这些字符串在原始示例中的字段名为"id"时不可用。对于这个问题,我认为最好使用一个叫做
to_entries
的过滤器。
to_entries
将对象的键和值都转换为值,使其可用。对象内的每个键值对都变成了我所称之为“entry”对象的一部分,它看起来像这样:{"key": some_key, "value": some_value}
。请注意,“key”和“value”字面上是字符串“key”和“value”,因此像{"243": "alpha", "244": "Beta"}
这样的对象会变成像[{"key": "243", "value": "alpha"}, {"key": "244", "value": "beta"}]
这样的数组。
这样可以使键可用,但在数据通过系统时,也可能难以跟踪数据的结构。这就是我发现将事物拆分为函数真正有帮助的地方。
cat input.json | jq '
def entry_to_list:
[ .key, .value.name, .value.create.date ];
def list_to_string:
"Details:" + .[0] + ", " + .[1] + ", " + .[2] ;
.newList | to_entries | map( entry_to_list | list_to_string )
'
输出:
[
"Details: 243, test, 2017-08-31 13:57:29",
"Details: 244, test, 2017-08-31 13:57:29"
]
使用这个版本,您可以获得一个中间步骤,其中包含像`["244", "test", "2017-08-31 13:57:29"]`这样的值,这为对结果进行排序提供了几个选项。(数组首先按照第一个字段排序,然后按照第二个字段排序,以此类推)
newList | to_entries | map(entry_to_list) | sort | map(list_to_string)
(在转换为字符串之前对条目进行排序)
newList | to_entries | map(entry_to_list) | min | list_to_string
(在转换为字符串之前选择最低的条目)
api-producing-json
为stdin
的循环?请参阅如何在本机消息传递主机中从stdin解析JSON? - guest271314