Comments 26
Вот тут
where { get("arr") int (0) > 5 }
не совсем понятно, что значит int (0) > 5. Нашел только
int(name: String)
int(idx: String)
а здесь, похоже, число. Кстати было бы совсем хорошо, если бы язык был описан (пусть только в рамках статьи) через формальную грамматику, с правилами вывода (тем более, что язык не очень сложный). Тогда бы и вопросов таких не возникало
Этот код возвращает вложенный объект «arr»:
Так как это тоже нода, для нее применяются все те же хелперы, например, получили нулевой элемент-число объекта «arr» и проверили что он больше пяти:
Однако Kotlin позволяет опционально опускать точку и получить ровно тоже самое:
Насчет того что в документации idx должно быть числом, да, вы правы, уже исправил.
Формальная грамматика Kotlin доступна здесь: kotlinlang.org/docs/reference/grammar.html
get("arr")
Так как это тоже нода, для нее применяются все те же хелперы, например, получили нулевой элемент-число объекта «arr» и проверили что он больше пяти:
get("arr").int(0) > 5
Однако Kotlin позволяет опционально опускать точку и получить ровно тоже самое:
get("arr")int(0) > 0
Насчет того что в документации idx должно быть числом, да, вы правы, уже исправил.
Формальная грамматика Kotlin доступна здесь: kotlinlang.org/docs/reference/grammar.html
такое ощущение, что это более компактный sql ))
Просто для сравнения можете привести код, эквивалентный примеру с jq?
У них не получится, первое действие в jq было выбрать ключ tickets тут такого пока нет) Хотя почитал комменты, видимо аналог это действия get(«tickets»)
Легко! Вот так
Или так
cat file.ndjson | analyze 'where{text("assigned_displayname")=="Матвей"} select{int("id")+"\t" +text("title")+"\t"+text("description")}'
Или так
cat file.ndjson | analyze 'where{text("assigned_displayname")=="Матвей"} select{"${int("id")}\t${text("title")}\t${text("description")}"}'
Все еще пропущен первый get tickets и есть мелкие ошибки) Но вижу) Правда не очень понятно зачем text(), но видимо это подсказка преобразователю. В целом не плохо, если нравится mysql. Я же mysql не люблю, поэтому предпочту более краткий синтаксис без слов select/where. Впрочем взять с гитхаба и сократить их в символы, например $_?, всегда можно, но вряд ли захочу.
И тут id это не инт, а текст. По формату json что-то в " это текст, даже если это целое-положительное. Поэтому лучше распознание такого куска добавить по умолчанию, т.е. все в кавычках это текст, а числа без них это числа с плавающей точкой. Всякие 0xf можно опустить XD тогда ваш код сократится до вменяемого
Если еще убрать необходимость писать все ключи в кавычках, то начнет напоминать jsqry где выбрать ключ это просто написать его, отфильтровать это написать фильтр в [квадратных скобках], а преобразовать вывод или вашим языком select пишется в {фигурных скобках}.
И тут id это не инт, а текст. По формату json что-то в " это текст, даже если это целое-положительное. Поэтому лучше распознание такого куска добавить по умолчанию, т.е. все в кавычках это текст, а числа без них это числа с плавающей точкой. Всякие 0xf можно опустить XD тогда ваш код сократится до вменяемого
analyze 'get("tickets") where {"assigned_displayname"=="Матвей"} select {"${"id"} ${"title"}\t${"description"}"}'
Если еще убрать необходимость писать все ключи в кавычках, то начнет напоминать jsqry где выбрать ключ это просто написать его, отфильтровать это написать фильтр в [квадратных скобках], а преобразовать вывод или вашим языком select пишется в {фигурных скобках}.
text(«field») отдаст нам объект String из jvm + будут достпны все его методы.
obj(«field») отдаст нам просто json-ноду jackson + будут доступны ее методы.
obj(«field») отдаст нам просто json-ноду jackson + будут доступны ее методы.
Действительно, в таком примере первый select/.map выглядят избыточно. Однако только до тех пор пока мы выбираем лишь одну ноду из родительского json. Представьте что вам нужно взять не только tickets а еще и пару его соседей, к примеру объект security_info. С kq это так:
Можно создать почти любой композитный объект из jvm.
.map{get("tickets") to get("security_info")}
// сделали пару из билета и секьюрных данных
Можно создать почти любой композитный объект из jvm.
Это прикольно, но с помощью fx (js) это тоже можно сделать, {...this.tickets, ...this.security_info}. Не сказать что это часто нужно и зачастую это свидетельство о том что структуру json придумывал человек редко пользующийся js, но это можно сделать.
А про text и obj, вы не очень поняли. В json по синтаксису сразу понятно где текст, где число, где массив, где хешмап. Поэтому лучше по умолчанию делать такие преобразования. А если как в моем примере id в json это строка, то можно уже преобразовывать явно. Т.е. видим «123» или «foo» это строка по умолчанию, так как взято в кавычки, но первое мы можем явно преобразовать к, например, int. Это я к тому, что в самом json всегда явно указаны типы, поэтому указывать их всякий раз при парсинге нет необходимости. Ну и да, cheatography.com/gaston/cheat-sheets/json в помощь, хотя там далеко не все что в современном json есть. Т.е. строки могут быть в одинарных кавычках, числа начинаться с 0x, 0o, 0b и т.д., ключи объектов далеко не всегда берут в кавычки и в крайних случаях может дойти до того, что все это объекты)
А про text и obj, вы не очень поняли. В json по синтаксису сразу понятно где текст, где число, где массив, где хешмап. Поэтому лучше по умолчанию делать такие преобразования. А если как в моем примере id в json это строка, то можно уже преобразовывать явно. Т.е. видим «123» или «foo» это строка по умолчанию, так как взято в кавычки, но первое мы можем явно преобразовать к, например, int. Это я к тому, что в самом json всегда явно указаны типы, поэтому указывать их всякий раз при парсинге нет необходимости. Ну и да, cheatography.com/gaston/cheat-sheets/json в помощь, хотя там далеко не все что в современном json есть. Т.е. строки могут быть в одинарных кавычках, числа начинаться с 0x, 0o, 0b и т.д., ключи объектов далеко не всегда берут в кавычки и в крайних случаях может дойти до того, что все это объекты)
Возможно я покажусь ретроградом — но зачем простую утилиту упаковывать в docker?
Изначально делал ее для запуска в k8s поде. + Чтобы не грузить мануал установкой jdk.
может тогда взять GraalVM и завернуть в небольшой самодостаточный бинарник?
Да, идея хорошая, надо попробовать
Весь день проводил эксперименты с graalvm native-image. Результаты неутешительные, при сборке в нативный файл теряются некие зависимости и в результате при старте приложение ругается что не может обнаружить класс
KotlinJsr223DefaultScriptEngineFactory
, чего нет с self-executable jar. Так что пока слишком сырая технология.Советую взглянуть на такое решение.
github.com/borkdude/jet/blob/master/doc/query.md
Единственное «НО»- язык запросов clojure.
Как следствие этого мощные возможности по работе с данными, но необходимость минимально погрузится (к слову сказать погружение должно пройти быстро и легко).
Зато получаем ЛЕГКИЙ, ПРОСТОЙ и МОЩНЫЙ язык для запросов и трансформаций.
Простой пример
Пример использования одного из JQ example (https://stedolan.github.io/jq/tutorial/)
github.com/borkdude/jet/blob/master/doc/query.md
Единственное «НО»- язык запросов clojure.
Как следствие этого мощные возможности по работе с данными, но необходимость минимально погрузится (к слову сказать погружение должно пройти быстро и легко).
Зато получаем ЛЕГКИЙ, ПРОСТОЙ и МОЩНЫЙ язык для запросов и трансформаций.
Простой пример
$ echo '{:a 1 :b 2 :c 3}' | jet --query '(select-keys [:a :b])'
{:a 1, :b 2}
$ echo '{:a {:b 1}}' | jet --query '[:a :b]'
1
Пример использования одного из JQ example (https://stedolan.github.io/jq/tutorial/)
$ curl -s 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | \
jet --from json --keywordize --to edn --pretty --query '
(map
{:message [:commit :message]
:name [:commit :committer :name]
:parents [:parents (map :html_url)]})'
Окей так как в примере идет мой код, написанный на коленке за пять минут вставлю свои пять копеек.
1) Что там в примере.
Это не очень дописанный баш скрипт для работы с api ubugtrack.com цель достать тикеты на меня. Полная версия
В ней например Ид проекта сейчас зашито константой, да и не делает этот скриптик ничего нужного. Может потом сделаю из него создание веток ну или хотя бы сообщений к коммитам.
2) В чем проблема.
В том что xkcd.ru/927 вы просто создали еще одну вещь со своими правилами. Для меня jq просто первое что пришло на ум когда в баше захотелось работать с json. Если бы действительно припекло я бы использовал ноду.
3) Что хочется.
Не очередной велосипед со своим синтаксисом, и не бойлерплейт код для парсинга json из ноды. Я хорошо знаю синтаксис js. Основной его минус при быстрой работе с json это то, что для обектов вида {5: {}, 20: {}} аналоги map достаточно многословны, например через Object.entries(json).map(([key, value]) => /* code */) ну или хотя бы Object.values. С этим приходится мириться, но это приятней чем изучить еще один синтаксис ради синтаксиса.
4) Что есть.
habr.com/ru/post/525808 Более приятный и близкий к js синтаксис, с явной примесью scala. Плюсом то, что прочитав примеры я понимаю что они делают, в отличии от написанного собой же кода на jq. Минус это все же немного другой синтаксис, хоть может он даже и лучше.
habr.com/ru/post/347808 То о чем я говорил, js сейчас знает куча программистов, и хоть он и подрос, он все же скриптовый язык, подходящий для написания коротких скриптов.
5) Я все же хочу написать свой велосипед.
Флаг в руки) Это полезно и развивает. Однако к моему примеру вряд ли ваш велосипед подойдет, ибо первое что я делаю это беру из пришедшего {tickets: [{...},...], ...} только tickets. И сходу не заметил у вас этого. Ну и во вторых я вряд ли буду использовать для скриптов строгую типизацию. Разве что если она действительно даст огромный выигрыш в затратах ресурсов. Хотя конечно для файлов размером с гигабайт есть vim, sed, grep, head, tail, и вроде больше в моем арсенале для них ничего. Сомневаюсь что ваш или приведенные мною парсеры на ура с ними справятся)
6) Бонусом как выглядел бы мой пример если бы я не поленился загуглить названия утилит, про существование которых знал
Еще один бонус fx в том что можно вернуть не только json, что может существенно сократить последующие преобразования. Для jsqry нашел лишь те способы преобразования что идут из коробки. А ну да jsqry поддерживает срезы в стиле Python [-2:] что тоже прикольно.
1) Что там в примере.
Это не очень дописанный баш скрипт для работы с api ubugtrack.com цель достать тикеты на меня. Полная версия
bug () {
local bug
bug=$(curl https://ubugtrack.com/api/$UBUGTRACK_API/project/3758/tickets/\?filter_status\=1 | jq '.tickets | map(select(.assigned_displayname=="Матвей"))' | jq '.[] | "\(.id) \(.title) \t \(.description)\n"' | sed -e 's/"\(.*\)"/\1/' -e 's/\\t/\t/' | fzf --delimiter='\t' --preview='echo -e {2}' --with-nth=1 | sed 's/^\([0-9]\+\).*/\1/')
if [ -n "$bug" ]
then
echo "You selected bug $bug"
fi
}
В ней например Ид проекта сейчас зашито константой, да и не делает этот скриптик ничего нужного. Может потом сделаю из него создание веток ну или хотя бы сообщений к коммитам.
2) В чем проблема.
В том что xkcd.ru/927 вы просто создали еще одну вещь со своими правилами. Для меня jq просто первое что пришло на ум когда в баше захотелось работать с json. Если бы действительно припекло я бы использовал ноду.
3) Что хочется.
Не очередной велосипед со своим синтаксисом, и не бойлерплейт код для парсинга json из ноды. Я хорошо знаю синтаксис js. Основной его минус при быстрой работе с json это то, что для обектов вида {5: {}, 20: {}} аналоги map достаточно многословны, например через Object.entries(json).map(([key, value]) => /* code */) ну или хотя бы Object.values. С этим приходится мириться, но это приятней чем изучить еще один синтаксис ради синтаксиса.
4) Что есть.
habr.com/ru/post/525808 Более приятный и близкий к js синтаксис, с явной примесью scala. Плюсом то, что прочитав примеры я понимаю что они делают, в отличии от написанного собой же кода на jq. Минус это все же немного другой синтаксис, хоть может он даже и лучше.
habr.com/ru/post/347808 То о чем я говорил, js сейчас знает куча программистов, и хоть он и подрос, он все же скриптовый язык, подходящий для написания коротких скриптов.
5) Я все же хочу написать свой велосипед.
Флаг в руки) Это полезно и развивает. Однако к моему примеру вряд ли ваш велосипед подойдет, ибо первое что я делаю это беру из пришедшего {tickets: [{...},...], ...} только tickets. И сходу не заметил у вас этого. Ну и во вторых я вряд ли буду использовать для скриптов строгую типизацию. Разве что если она действительно даст огромный выигрыш в затратах ресурсов. Хотя конечно для файлов размером с гигабайт есть vim, sed, grep, head, tail, и вроде больше в моем арсенале для них ничего. Сомневаюсь что ваш или приведенные мною парсеры на ура с ними справятся)
6) Бонусом как выглядел бы мой пример если бы я не поленился загуглить названия утилит, про существование которых знал
#Оригинал
jq '.tickets | map(select(.assigned_displayname=="Матвей"))' | jq '.[] | "\(.id) \(.title) \t \(.description)\n"'
#fx
fx 'this.tickets.filter(t => t.assigned_displayname == "Матвей").map(t => `${t.id} ${t.title} \t ${t.description}`)'
# для fx мне не потребовался дополнительный пайп, и до кучи я смог написать всю строчку без подглядывания в документацию
#jsqry
jsqry 'tickets [_.assigned_displayname == "Матвей"] {`${_.id} ${_.title} \t ${_.description}`}'
# тут пришлось чуть больше смотреть на примеры, но все же это самый краткий вариант
Еще один бонус fx в том что можно вернуть не только json, что может существенно сократить последующие преобразования. Для jsqry нашел лишь те способы преобразования что идут из коробки. А ну да jsqry поддерживает срезы в стиле Python [-2:] что тоже прикольно.
для написания скриптов на js есть zx github.com/google/zx
Наверное я оставлю эту ссылку здесь. coderoad.ru/1955505/%D0%A0%D0%B0%D0%B7%D0%B1%D0%BE%D1%80-JSON-%D1%81-%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%D1%8C%D1%8E-%D0%B8%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2-Unix В ответах много чего, вплоть до того что например в powershell проблемы с json нет)
Тот случай, когда статья на хабре больше кодовой базы проекта =)
Поздравляю, вы изобрели AQL
А что, если просто использовать powershell?
PS C:\Projects\Temp> Get-Content 'test.ndjson' | ConvertFrom-Json | where {$_.size -eq '245'}
4880123 245 True
Sign up to leave a comment.
Современный JSON процессор