Преобразование, работающее с небольшими файлами, завершается неудачно при использовании опции «--stream» (требуется из-за размера файла) - PullRequest
4 голосов
/ 09 апреля 2019

Фрагмент JQ-игры: https://jqplay.org/s/D5-FZl8wOs

Я использую jq для выравнивания массива json, который будет использоваться для sql.

JSON:

{
"0123":[
    {"i":0,"p":"file 1","l":100},
    {"i":1,"p":"file 2","l":200}
    ],
"0234":[
    {"i":0,"p":"file 1","l":100},
    {"i":1,"p":"file 2","l":200}
    ]
}

JQ:

jq -r to_entries[] | {hash: .key, val: .value[]} | [.hash, .val.i, .val.p, .val.l]

Желаемый вывод:

[
  "0123",
  0,
  "file 1",
  100
]
[
  "0123",
  1,
  "file 2",
  200
]
[
  "0234",
  0,
  "file 1",
  100
]
[
  "0234",
  1,
  "file 2",
  200
]

Вышеописанное работало только тогда, когда файл был небольшим, но теперь я получаю ошибки памяти / ОС убивает его по мере его увеличения.

Если я передаю параметр --stream, я получаю ошибку:

jq: error (at <stdin>:9): Cannot index array with string "i"

Как я могу решить это?

Ответы [ 2 ]

2 голосов
/ 09 апреля 2019

что-то вроде следующего будет работать для вашего образца ввода .

foreach inputs as $pv ([[],[]]; # [A, B]
  if ($pv|length) == 2          # if pv is a path-value pair
  then .[0] |= if . == []       # if A is empty
    then . + [$pv[0][0],$pv[1]] # add first key from path definition and the value located at path to A
    else . + [$pv[1]] end       # add value to A
  else [[],.[0]] end;           # move A to B's place, leave A empty
  if .[0] == [] and .[1] != []  # if A is empty but B is not
  then .[1] else empty end      # print B
)

призывание:

jq --stream -n 'foreach inputs as $pv ([[],[]]; if ($pv|length) == 2 then (.[0] |= if . == [] then . + [$pv[0][0],$pv[1]] else . + [$pv[1]] end) else [[],.[0]] end; if .[0] == [] and .[1] != [] then .[1] else empty end)' file

jqplay: https://jqplay.org/s/Q81EZahkjG

1 голос
/ 12 апреля 2019

Мне нужен способ заставить to_entries [] работать с потоковой передачей

Вот определение, которое делает именно это:

def atomize(s):
    fromstream(foreach s as $in ( {previous:null, emit: null};
      if ($in | length == 2) and ($in|.[0][0]) != .previous and .previous != null
      then {emit: [[.previous]], previous: $in|.[0][0]}
      else { previous: ($in|.[0][0]), emit: null}
      end;
      (.emit // empty), $in) ) ;

С помощью этого def вы можете использовать свой фильтр, добавив atomize(inputs), предполагая, что вы вызываете jq с опциями -n и --stream. То есть ваш основной фильтр будет:

atomize(inputs)
| to_entries[]
| {hash: .key, val: .value[]}
| [.hash, .val.i, .val.p, .val.l]

Альтернативный

Если JSON полностью регулярен, как в примере, вы можете написать:

atomize(inputs)
| to_entries[]
| .value[] as $value
| [.key, $value[]]
...