Перейти к основному содержимому
Версия: 2.0 (WIP)

Операторы пути

Операторы пути лежат в основе декларативной природы модели обработки map/filter/reduce в JSONata.

. (Map)

Оператор точки — один из фундаментальных элементов выражений JSONata. Он реализует функцию «для каждого» (for each) или map, распространённую во многих функциональных языках.

Оператор точки выполняет следующую логику:

  • Выражение в левой части (LHS) вычисляется и формирует массив значений.
    • Если оно вычисляется в одно значение, оно рассматривается как массив, содержащий это одно значение.
    • Если оно не возвращает ничего (нет совпадения или пустой массив), результатом выражения с оператором также будет отсутствие значения.
  • По очереди для каждого значения в массиве LHS:
    • Значение становится контекстом и служит основой для любого относительного выражения пути в правой части (RHS). Оно также доступно в RHS через символ $.
    • Выражение RHS вычисляется в значение, массив значений или отсутствие значения. Эти значения добавляются в общий массив результатов оператора.
  • Возвращается объединённый результат оператора.

Оператор левоассоциативен: выражение a.b.c.d вычисляется как ((a.b).c).d, то есть слева направо.

Примеры

  • Address.City => "Winchester"
  • Phone.number => [ "0203 544 1234", "01962 001234", "01962 001235", "077 7700 1234" ]
  • Account.Order.Product.(Price * Quantity) => [ 68.9, 21.67, 137.8, 107.99 ]
  • Account.Order.OrderID.$uppercase() => [ "ORDER103", "ORDER104"]

[ ... ] (Фильтр)

Оператор фильтра (также предикат) выбирает из входной последовательности только элементы, удовлетворяющие выражению-предикату в квадратных скобках.

Если выражение-предикат — целое число или вычисляется в целое число, в результирующую последовательность попадёт только элемент входной последовательности с этой позицией (нумерация с нуля). Нецелое число округляется вниз до ближайшего целого.

Если выражение-предикат является массивом целых чисел или вычисляется в такой массив, в результирующую последовательность попадут только элементы входной последовательности с этими позициями (нумерация с нуля).

Если выражение-предикат вычисляется в любое другое значение, оно приводится к логическому значению так же, как функцией $boolean(). Если результат равен true, элемент сохраняется в результирующей последовательности; иначе отбрасывается.

Подробнее и с примерами см. навигацию по массивам JSON и предикаты.

^( ... ) (Сортировка)

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

По умолчанию массив сортируется по возрастанию. Например, Account.Order.Product^(Price) сортирует все продукты в порядке увеличения цены (Price — числовое поле объекта Product).

Чтобы отсортировать по убыванию, перед выражением сортировки следует поставить >. Например, Account.Order.Product^(>Price) сортирует продукты по убыванию цены. Символ < можно использовать для явного указания сортировки по возрастанию, хотя это поведение установлено по умолчанию.

Вторичные и последующие выражения сортировки указываются через запятую (,). Вторичное выражение определяет порядок, если первичное присвоило двум значениям одинаковый ранг. Например, Account.Order.Product^(>Price, <Quantity) сначала сортирует продукты по убыванию цены, а продукты с одинаковой ценой — по возрастанию количества.

Выражениями сортировки могут быть любые корректные выражения JSONata, вычисляющиеся в число или строку. Если выражение возвращает строку, массив сортируется по порядку кодовых точек Unicode.

Примеры

  • Account.Order.Product^(Price * Quantity) => Возрастающий порядок произведения цены на количество.
  • student[type='fulltime']^(DoB).name => Имена всех студентов очной формы, отсортированные по дате рождения (значение DoB имеет формат даты ISO 8601).

{ ... } (Reduce)

Оператор свёртки можно использовать как последний этап выражения пути, чтобы сгруппировать и агрегировать входную последовательность в один объект. Пары ключ/значение в фигурных скобках определяют группировки (путём вычисления выражения ключа) и агрегированные значения для каждой группы. Подробнее см. группировку и агрегацию.

* (Подстановочный знак)

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

** (Потомки)

Этот подстановочный знак рекурсивно выбирает значения всех свойств контекстного объекта, а также свойства объектов, содержащихся в этих значениях, по мере обхода иерархии. См. навигацию по произвольной глубине.

% (Родитель)

Этот оператор выбирает «родителя» текущего контекстного значения. Под «родителем» здесь понимается охватывающий объект, содержащий свойство, представляющее контекстное значение.

Это единственная операция, которая ищет «назад» во входной структуре данных. Она реализована статическим анализом выражения во время компиляции и может использоваться только в выражениях, которые изначально переходят через целевое родительское значение. Если по какой-либо причине положение родителя определить нельзя, возникает статическая ошибка S0217.

Пример

Account.Order.Product.{
'Product': `Product Name`,
'Order': %.OrderID,
'Account': %.%.`Account Name`
}

Это возвращает массив объектов для каждого продукта в каждом заказе каждой учётной записи. Информация из охватывающих объектов Order и Account доступна через оператор родителя. Повторяющаяся комбинация %.%. используется для доступа к прародителю и более высоким предкам.

# (Привязка переменной позиции)

Этот оператор определяет позицию текущего элемента контекста в последовательности. Его можно использовать после любого этапа map, filter или сортировки в пути. Переменная доступна на последующих этапах пути (например, в предикатах фильтра) и выходит из области видимости в конце выражения пути.

Пример

library.books#$i['Kernighan' in authors].{
'title': title,
'index': $i
}

Это возвращает массив объектов для каждой книги библиотеки, среди авторов которой есть Kernighan. Каждый объект содержит название книги и её позицию в массиве книг до фильтрации.

@ (Привязка переменной контекста)

Этот оператор привязывает текущий элемент контекста ($) к именованной переменной. Его можно использовать только непосредственно после этапа map, но не после этапа filter или сортировки. Привязка переменной остаётся в области видимости до конца выражения пути.

Поскольку текущий контекст явно привязан к именованной переменной, он переносится как контекст следующего этапа пути. Например, во фрагменте пути library.loans@$l.books массив займов является свойством объекта библиотеки, и каждый заём по очереди привязывается к переменной $l. Затем выбирается массив книг, который тоже является свойством объекта библиотеки.

Этот оператор позволяет выполнять соединения данных внутри пути, поскольку может создавать перекрёстные ссылки между объектами.

Пример

library.loans@$l.books@$b[$l.isbn=$b.isbn].{
'title': $b.title,
'customer': $l.customer
}

Это выполняет «внутреннее соединение» (inner join) объектов массива займов с объектами массива книг, где ISBN совпадают между структурами.

Блочные выражения могут расширить область действия перекрёстных ссылок, как показано в примере:

(library.loans)@$l.(catalog.books)@$b[$l.isbn=$b.isbn].{
'title': $b.title,
'customer': $l.customer
}