Расширьте довольно большой объект до более мелких с помощью --stream - PullRequest
1 голос
/ 08 мая 2020

У меня есть следующее рабочее преобразование 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 довольно велик - представьте себе тысячи записей в поле «значения» в приведенном выше примере. Я использую sh для выполнения этого точного преобразования в режиме потока jq с целью избежать нехватки памяти.

Я пробовал использовать jq foreach безрезультатно. Я не могу найти способ сохранить значение "key1", на которое будет ссылаться при обработке записей в "values".

Пример, используя тот же ввод, что и в рабочем примере:

$ 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"]]}

Мне нужно ссылаться на значение «key1» при обработке строк 2 и 3 выше и так далее для остальных ключей.

Повторяю, я хочу получить точный результат из непотоковой версии.

Ответы [ 2 ]

3 голосов
/ 08 мая 2020

foreach не требуется в этом случае.

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

Примечание: это отвечает исходной версии OP .

1 голос
/ 09 мая 2020

Вот решение с использованием --stream и foreach, которое можно использовать для потока JSON объектов описанного типа. Обратите внимание, что предполагается, что «ключ» стоит перед «значением» в каждом из объектов верхнего уровня.

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