jq, разделите огромный массив json и сохраните в файл с именем со значением

у меня есть json, содержащий массив объектов, каждый объект содержит уникальное значение в:

"id":"value"

я следовал этому другому ответу, и я могу разделить весь документ на несколько файлов, используя jq и awk

jq -c ".[]" big.json | gawk '{print > "doc00" NR ".json";}'

таким образом выходные файлы именуются последовательно.
как я могу назвать файлы, используя значение id?


person George Livanoss    schedule 16.05.2019    source источник


Ответы (3)


Для каждого элемента в массиве напечатайте идентификатор и сам элемент в двух отдельных строках, таким образом, вы можете получить идентификатор из строк с нечетными номерами и напечатать строки с четными номерами в файлы с именем с идентификатором.

jq -cr '.[] | .id, .' big.json | awk 'NR%2{f=$0".json";next} {print >f;close(f)}'
person oguz ismail    schedule 16.05.2019
comment
OP не использовал параметр командной строки -r, и его использование сопряжено с потенциальным риском (связанным со строками со встроенными символами новой строки), о котором следует упомянуть. Если известно, что печатаемые объекты JSON не являются строками JSON, то использование -r бессмысленно, поэтому в целом было бы лучше опустить его, если только нельзя установить, что это действительно необходимо. - person peak; 16.05.2019
comment
@peak Да, вы правы, но если мы отбросим -r, мы должны удалить двойные кавычки в скрипте awk, что мне не кажется хорошей идеей:/ - person oguz ismail; 16.05.2019
comment
А если у элемента массива есть ключ, то он гарантированно будет объектом, и -r его не изменит, верно? - person oguz ismail; 16.05.2019
comment
Да, но в конкретном случае, описанном OP, существует риск того, что .id может содержать новую строку. - person peak; 16.05.2019
comment
о да, это был бы облом - person oguz ismail; 16.05.2019

Использование .id как части имени файла сопряжено с риском.

Во-первых, существует потенциальная проблема встроенных символов новой строки.

Во-вторых, существует проблема «зарезервированных» символов, особенно «/».

В-третьих, Windows имеет многочисленные ограничения на имена файлов — см., например. https://gist.github.com/doctaphred/d01d05291546186941e1b7ddc02034d3.

Кроме того, если используется параметр jq -r, как предлагается в другом сообщении на этой странице, то значения .id "1" и 1 будут сопоставлены с 1, что приведет к потере данных, если в awk используется «>».

Итак, вот решение, которое иллюстрирует, как можно обеспечить безопасность в среде OS X или *ix, и которое имеет большое значение для безопасного решения для Windows:

jq -c '.[]
       | (.id | if type == "number" then .
                else tostring | gsub("[^A-Za-z0-9-_]";"+") end), .' |
awk '
  function fn(s) { sub(/^\"/,"",s); sub(/\"$/,"",s); return s ".json"; }
  NR%2{f=fn($0); next} 
  {print >> f; close(f);}
' 

Обратите особое внимание на использование «>>», чтобы избежать потери данных в случае конфликта имен файлов.

person peak    schedule 16.05.2019

Поскольку в описании проблемы указано, что входной массив огромен, возможно, стоит рассмотреть возможность использования потокового синтаксического анализатора jq. Как правило, это целесообразно, если входной JSON слишком велик для чтения в память или если важной целью является снижение требований к памяти компьютера.

Вкратце, вместо обычного вызова jq добавляются параметры командной строки -n и --stream и заменяется первоначальный .[] на:

fromstream(1|truncate_stream(inputs))

Обработка разделения может быть выполнена, как описано в другом месте на этой странице.

person peak    schedule 17.05.2019