使用--stream将相当大的对象扩展为较小的对象

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用--stream将相当大的对象扩展为较小的对象相关的知识,希望对你有一定的参考价值。

我有以下工作的jq转换:

$ echo '{"key": "key1", "value": {"one": 1, "two": 2}}' | jq --compact-output '.key as $key|.value|to_entries|map({key: ($key), member:.key, score:(.value|tostring)})|.[]'

将正确产生所需的输出:

{"key":"key1","member":"one","score":"1"}
{"key":"key1","member":"two","score":"2"}

输入json很大-假设上面示例的“ values”字段中有成千上万个条目。我希望在jq流模式下执行此精确转换,目的是避免内存压力。

我尝试使用jq foreach无济于事。我找不到一种方法来存储“ key1”值,该值在处理“值”中的条目时将被引用。

示例,使用与工作示例相同的输入:

$ echo '{"key": "key1", "value": {"one": 1, "two": 2}}'| jq -c --stream 'foreach . as $input ({};{in: $input};.)'

{"in":[["key"],"key1"]}
{"in":[["value","one"],1]}
{"in":[["value","two"],2]}
{"in":[["value","two"]]}
{"in":[["value"]]}

在处理上面的第2行和第3行时,我需要引用值“ key1”。

重申一下,我希望从非流版本中获得准确的输出。

答案

foreach在这种情况下是不必要的。

{key: .[1]}
+ ( inputs
    | select(length == 2)
    | {member: .[0][1], score: .[1]}
  )
另一答案

您可以通过添加jq字段来启用--stream的流解析器,并且使用fromstream(inputs)应该像对非流式处理部分所做的那样将输入输入到过滤器中。因此,以下应该可以正常工作。

jq -nc --stream 'fromstream(inputs) | .key as $key |.value | to_entries[] | map({key: $key, member:.key, score:(.value|tostring)})'

我无法在大型JSON上对性能进行基准测试,但是它应比非流版本更好。

另一答案

这是根据要求使用--stream的解决方案:

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)'

以上是关于使用--stream将相当大的对象扩展为较小的对象的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Blender 脚本删除场景中较小的多个对象?

用JAVA实现--15位身份证扩展为18位身份证

Elasticsearch:Dot expander processor - 将带点的字段 foor.bar 扩展为 Object

Elasticsearch:Dot expander processor - 将带点的字段 foor.bar 扩展为 Object

iOS:将大型 XIB 重构为几个较小的 XIB 文件以提高速度

将一个大的 json 文件拆分为多个较小的文件