Итеративная обработка данных
В Серверном API нет методов, реализующих пагинацию, как, например, в операции GET Table API. Однако без пагинации, при выборке большого количества записей из таблицы, мы можем столкнуться с проблемой снижения производительности системы и ограничением по памяти.
Для решения данной проблемы можно разделить обработку данных на “порции”.
Код ниже итеративно извлекает и обрабатывает все записи из таблицы itsm_task блоками по 1000 записей:
const LIMIT = 1000;
let recordCount = LIMIT;
let lastRecordId = '0';
while (recordCount === LIMIT) {
const record = new SimpleRecord('itsm_task');
record.addQuery('sys_id', '>', lastRecordId);
record.orderBy('sys_id');
record.setLimit(LIMIT);
record.query();
recordCount = record.getRowCount();
while (record.next()) {
lastRecordId = record.sys_id;
}
}
Постраничный доступ к данным
На основе представленной логики, можно организовать постраничную выборку данных, например, через функцию getNextPage, которая реализует одну итерацию пагинации (одну “страницу” данных) из таблицы, задаваемой через параметр tableName, начиная с записи после startRecordId. Начальное значение startRecordId должно быть равно максимально возможному sys_id, чтобы начать с новых записей, в противном случае на первой “странице” будут доступны наиболее старые записи.
function getNextPage(tableName, limit = 10, startRecordId = 'ffffffffffffffffffffffffffffffff') {
const record = new SimpleRecord(tableName);
record.addQuery('sys_id', '<', startRecordId);
record.orderByDesc('sys_id');
record.setLimit(limit);
record.selectAttributes(['sys_id', 'number']);
record.query();
const data = [];
let lastRecordId = startRecordId;
while (record.next()) {
lastRecordId = record.getValue('sys_id');
data.push(record.getAttributes());
}
return { data, lastRecordId }; // {"data":[],"lastRecordId":""}
}
Если нужно получить n-ую страницу, можно сделать обертку в цикл:
function getPage(tableName, pageNumber, pageSize = 10) {
let lastRecordId = 'ffffffffffffffffffffffffffffffff';
let currentPage = 1;
let page;
while (currentPage <= pageNumber) {
page = getNextPage(tableName, pageSize, lastRecordId);
lastRecordId = page.lastRecordId;
currentPage++;
}
return page; // {"data":[],"lastRecordId":""}
}
Важно заметить, что функция getPage
неэффективна при больших значениях pageNumber, т.к. при попытке получить, например, 100-ю страницу, функция вызывает getNextPage
100 раз. Это не критично при малых объёмах, но сильно влияет на производительность при больших значениях pageNumber
.
Table API
Проблему производительности можно решить воспользовавшись Table API и SimpleRestRequest. С помощью SimpleWebService sws.restRequestV1()
создается объект SimpleRestRequest и далее с помощью его методов setRequestMethod
, setRequestUrl
и прочих, формируется запрос к Table API:
function getPage(tableName, pageNumber = 1, pageSize = 10) {
const request = sws.restRequestV1();
request.setRequestMethod('GET');
const instanceUri = ss.getProperty('simple.instance.uri');
request.setRequestUrl(`https://${instanceUri}/rest/v1/table/${tableName}`);
request.setQueryParameter('sysparm_fields', 'number,sys_id');
request.setRequestHeader('Authorization', `Bearer XXXXXXXX`);
request.setQueryParameter('sysparm_page', pageNumber.toString());
request.setQueryParameter('sysparm_limit', pageSize.toString());
const response = JSON.parse(request.execute().getBody());
return response; // {"status":"OK","data":[]}
}
Важно: Table API требует авторизации, поддерживаются Basic Auth и Bearer Token.