Массивы в Ninox

Простые массивы

Работать с массивами текстов или чисел просто:

var myArray := ["a", "b", "d"];

index(myArray, "b");
myArray := array(myArray, ["c"]);

myArray order this;

Сортировать можно также с помощью order, sort и unsort — для текстовых и числовых массивов.
Другие функции для работы с массивами описаны в документации Ninox.

Двумерные массивы

Ninox не поддерживает двумерные массивы напрямую. Вместо них используйте массив объектов JSON.
Например, отсортируем массив по второму элементу поля d2:

var myArray := [{'d2':["a", "Z"]}, {'d2':["b", "B"]}, {'d2':["c", "C"]}, {'d2':["d", "D"]}];

(myArray order by item('d2', 1));

Этот код возвращает: [{"d2":["b","B"]},{"d2":["c","C"]},{"d2":["d","D"]},{"d2":["a","Z"]}]

Фильтрация массивов

Массивы фильтруются так же, как результат select. Для текстовых и числовых массивов используйте this, чтобы обратиться к фильтруемому значению:

var myArray := ["Jan", "Fred", "Jacques"];
myArray[this like "J"] order this;

Для массивов JSON обращайтесь прямо к ключу:

var myArray := [
  { 'prénom' : "Jan", nom : "Augustin" },
  { 'prénom' : "Fred", nom : "Baillot" },
  { 'prénom' : "Jacques", nom : "Tur" }
];

myArray[nom like "i"] order 'prénom';

Этот код возвращает массив JSON: [{"prénom":"Fred","nom":"Baillot"}, {"prénom":"Jan","nom":"Augustin"}]

Собственные действия над массивами JSON

Для массивов JSON можно добавить блок кода (в скобках), выполняемый на каждом витке. Как и в for in, тип получаемого массива определяется последней строкой блока.

Пример: вычислим длину полных имён (prénom + nom):

var myArray := [
  { 'prénom' : "Leo", nom : "Martin" },
  { 'prénom' : "Paul", nom : "Garnet" },
  { 'prénom' : "Pierre", nom : "Dur" }
];

var nameLengths := myArray[nom like "a"].(
    var fullName := ---{'prénom'} {nom}---;
    length(fullName)
);
nameLengths;

Этот код возвращает массив чисел [10, 11] — длины полных имён.

Создание пустого типизированного массива

В Ninox обычный приём для создания пустого массива, сохраняющего нужный тип записей, — выполнить select с фильтром where false.
Запрос не возвращает ни одной записи, но сохраняет тип элементов массива.

"Empty Invoice Item array:";
let t := (select 'Invoice Item' where false);
  • Теперь t — это массив, элементы которого имеют тип Invoice Item.
  • Поскольку он пуст, но типизирован, его можно смело брать за отправную точку для операций array().

Почему не просто []?

Литерал [] — это нетипизированный массив. Часто он работает, но в сочетании с array() над наборами записей Ninox может пожаловаться на несовпадение типов.
Приём select … where false полностью снимает эту проблему.

Создание пустого массива для простых типов (число, текст, JSON…)

Когда нужен пустой массив скалярных значений — чисел, строк или объектов JSON, — нет таблицы, из которой можно было бы сделать select.
Но типизированный пустой массив всё равно можно получить: создайте [] с одним фиктивным элементом и тут же отфильтруйте его:

"Empty number / text / JSON array:";
let t := [1][false];   "t is now an empty but number typed array";

[1] даёт числовой массив из одного элемента; фильтр [false] убирает этот элемент, оставляя пустой массив, сохранивший тип число.
Если нужны другие типы, поставьте вместо 1 текстовый литерал или литерал JSON.

Развёртывание двумерного массива

Каждый Invoice содержит собственный подмассив Invoice Items. Чтобы получить один общий список со всеми позициями всех счетов, переберите счета и соедините их подмассивы.

"Initialize empty array:";
let t := (select 'Invoice Item' where false);

"Iterate over each invoice and add its items:";
for i in Invoices do
    t := array(t, i.'Invoice Items')
end;

"Return the flattened list:";
t

Как это работает

  1. for i in Invoices do … end перебирает все записи Invoice.
  2. array(t, i.'Invoice Items') соединяет текущее значение t с массивом позиций этого счёта.
    • На первом витке добавляются позиции первого счёта.
    • На втором — позиции второго счёта, и так далее.
  3. По окончании цикла t содержит все позиции всех счетов в одном плоском массиве.

Теперь можно, например, вызвать count(t), чтобы узнать общее число позиций, или напрямую перебирать и фильтровать t.