使用 --stream 将相当大的对象扩展为较小的对象
Expand a fairly large object to smaller objects using --stream
我有以下有效的 jq 转换。输入文件(input.jsonl):
{"key": "key1", "value": {"one": 1, "two": 2}}
{"key": "key2", "value": {"three": 3, "four": 4}}
jq变换:
$ jq --compact-output '.key as $key|.value|to_entries|map({key: ($key), member:.key, score:(.value|tostring)})|.[]' input.jsonl
正确生成所需的输出:
{"key":"key1","member":"one","score":"1"}
{"key":"key1","member":"two","score":"2"}
{"key":"key2","member":"three","score":"3"}
{"key":"key2","member":"four","score":"4"}
输入 json 非常大 - 想象一下上述示例的 "values" 字段中有数千个条目。我希望在 jq 流模式下执行这个精确的转换,目的是避免内存压力。
我试过使用 jq foreach
无济于事。我找不到一种方法来存储要在处理 "values" 中的条目时引用的 "key1" 值。
示例,使用与工作示例相同的输入:
$ jq -c --stream 'foreach . as $input ({};{in: $input};.)' input.jsonl
{"in":[["key"],"key1"]}
{"in":[["value","one"],1]}
{"in":[["value","two"],2]}
{"in":[["value","two"]]}
{"in":[["value"]]}
{"in":[["key"],"key2"]}
{"in":[["value","three"],3]}
{"in":[["value","four"],4]}
{"in":[["value","four"]]}
{"in":[["value"]]}
我需要在处理上面的第 2 行和第 3 行时引用值 "key1",以此类推处理剩余的键。
重申一下,我想要非流版本的准确输出。
foreach
对于这种情况是不必要的。
{key: .[1]}
+ ( inputs
| select(length == 2)
| {member: .[0][1], score: .[1]}
)
注意:这回答了 the initial version of OP。
这是一个使用 --stream 和 foreach
的解决方案,可用于描述类型的 JSON 对象流。请注意,它假定 "key" 在每个顶级对象中出现在 "value" 之前。
echo '{"key": "key1", "value": {"one": 1, "two": 2}}' |
jq -n --stream -c 'foreach inputs as $in (null;
if $in|length == 2
then if $in[0][0] == "key" then .key=$in[1]
elif $in[0][0] == "value"
then .emit = {key: .key, member: $in[0][1], score: $in[1]}
else .emit=null end
else .emit=null end;
select(.emit) | .emit)'
我有以下有效的 jq 转换。输入文件(input.jsonl):
{"key": "key1", "value": {"one": 1, "two": 2}}
{"key": "key2", "value": {"three": 3, "four": 4}}
jq变换:
$ jq --compact-output '.key as $key|.value|to_entries|map({key: ($key), member:.key, score:(.value|tostring)})|.[]' input.jsonl
正确生成所需的输出:
{"key":"key1","member":"one","score":"1"}
{"key":"key1","member":"two","score":"2"}
{"key":"key2","member":"three","score":"3"}
{"key":"key2","member":"four","score":"4"}
输入 json 非常大 - 想象一下上述示例的 "values" 字段中有数千个条目。我希望在 jq 流模式下执行这个精确的转换,目的是避免内存压力。
我试过使用 jq foreach
无济于事。我找不到一种方法来存储要在处理 "values" 中的条目时引用的 "key1" 值。
示例,使用与工作示例相同的输入:
$ jq -c --stream 'foreach . as $input ({};{in: $input};.)' input.jsonl
{"in":[["key"],"key1"]}
{"in":[["value","one"],1]}
{"in":[["value","two"],2]}
{"in":[["value","two"]]}
{"in":[["value"]]}
{"in":[["key"],"key2"]}
{"in":[["value","three"],3]}
{"in":[["value","four"],4]}
{"in":[["value","four"]]}
{"in":[["value"]]}
我需要在处理上面的第 2 行和第 3 行时引用值 "key1",以此类推处理剩余的键。
重申一下,我想要非流版本的准确输出。
foreach
对于这种情况是不必要的。
{key: .[1]}
+ ( inputs
| select(length == 2)
| {member: .[0][1], score: .[1]}
)
注意:这回答了 the initial version of OP。
这是一个使用 --stream 和 foreach
的解决方案,可用于描述类型的 JSON 对象流。请注意,它假定 "key" 在每个顶级对象中出现在 "value" 之前。
echo '{"key": "key1", "value": {"one": 1, "two": 2}}' |
jq -n --stream -c 'foreach inputs as $in (null;
if $in|length == 2
then if $in[0][0] == "key" then .key=$in[1]
elif $in[0][0] == "value"
then .emit = {key: .key, member: $in[0][1], score: $in[1]}
else .emit=null end
else .emit=null end;
select(.emit) | .emit)'