Данный пакет является дополнением к YDB-SDK (NodeJS SDK для Yandex Database).
В этом документе также приведена документация по YDB-SDK.
Предназначение пакета - уменьшить размер boilerplate для манипуляции с таблицами. Например, в оригинальном SDK Вы должны написать около 90 строк кода для работы с одной таблицей (см. пример в examples/basic-example-old/data-helpers.ts) При этом сам код изобилует многочисленными повторениями в которых достаточно просто совершить опечатку.
Предлагается написать небольшую управляющую структуру вида
const series = {
seriesId: { val: 0, pt: Pt.UINT64, opt: 'r', pk: true },
title: { val: 'title', pt: Pt.UTF8, opt: 0 },
};
см. пример (examples/basic-example-new-way/table-definitions.ts)
К этой структуре добавляется несколько простых строк с авто выводом типа на основе управляющей структуры, описанием самого класса и его инициализацией:
export type ISeries = ConvertStructToTypes<typeof series>;
export class Series extends TypedDataDefs {
constructor(data: ISeries) {
super(data);
}
}
Series.initTableDef(databaseName, 'series', series);
После этого Вы можете создавать/удалять таблицу, вставлять данные в таблицу (одиночные и групповые.)
- Методы пакета и порядок работы
- Создание базы
- Формирование ключа для доступа к YDB
- Настройка подключения к базе данных
- Улучшение старой системы описания таблиц
- Новая структура формирования описания таблиц
- Краткая информация по работе с YDB SDK
- Драйвер
- Клиент
- Сессия
- Повторы (retries)
- Таймауты
- Варианты авторизации в базе данных
- Получить сессию
- Повторы при ошибке
- Запросы к YDB
- Начать/завершить транзакцию
- Обычные запросы
- Скан запросы
- Драйвер
- Методы хелперы для работы с YDB-SDK
- Определитесь с методом авторизации в YDB (более подробно возможные методы авторизации описаны в соответствующем разделе данного руководства). В примере использован метод авторизации с использованием авторизованного ключа сервисного аккаунта, этот ключ нужно записать в файл service_account_key_file.json.
Путь к этому файлу необходимо указать в env.local в переменной YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS.
Возможные варианты env переменных указаны в YDB-SDK тут - Если Вы используете авторизацию с использованием авторизованного ключа сервисного аккаунта (рекомендуется для приложений кроме функций) то сформируйте ключ как написано здесь
- Инициализируйте драйвер
Один из возможных методов инициализации драйвера показан в примере examples/utils/ydb-functions.ts - Получите сессию с помощью которой Вы будете выполнять запросы. Сделать это можно с помощью методов withSession и withSessionRetry
- Стандартный способ выполнения запросов - использовать методы класса Session.
Например executeQuery - Для полного чтения таблицы (по кускам) используйте streamReadTable, для полного чтения результатов запроса - streamExecuteScanQuery
- upsertToDB - upsert одной записи. Для работы метода достаточно заполнить только обязательные поля (создать экземпляр класса с обязательными полями). Остальные поля будут не затронуты запросом, но если Вы вставляете новую запись, то не указанные Вами поля будут установлены в null. Метод применятся к текущему экземпляру класса TypedDataDefs.
- replaceSeriesToDB - replace в базу массива записей класса. Для работы метода достаточно заполнить только обязательные поля. Остальные поля автоматически будут установлены в null и соответственно будут установлены в null в YDB.
- createDBTable - создает таблицу в Yandex database на основе управляющей структуры и имени таблицы, переданной при вызове метода initTableDef
- dropDBTable - удаляет таблицу
Создайте serverless базу YDB согласно документации (либо используя terraform)
Отличный пример от Виктора Кузенного создания ресурсов с помощью terraform Вы можете посмотреть тут
В директории examples необходимо сформировать ключ для доступа к базе. Ключ будет сформирован в файле service_account_key_file.json
Запустите команду: (если Вы под windows - то лучше запускать из wsl - в противном случае Вам необходимо убрать слеши из команды)
yc iam key create \
--folder-id <идентификатор каталога> \
--service-account-name <имя сервисного аккаунта> \
--output service_account_key_file.json
Про установку и настройку yc прочитайте тут:
https://cloud.yandex.ru/docs/cli/quickstart
Создайте файл env.local в корневой директории. Скопируйте туда строку : YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS=service_account_key_file.json (готовый пример файла уже приведен в данном проекте, в данном файле секреты отсутствуют)
Перейдите в консоль YDB, создайте базу данных и Вы увидите экран с параметрами Вашей базы. Нажмите на нее и заполните в файле env.local поля: DOCUMENT_API_ENDPOINT и DATABASENAME
Попутно отмечу что базу данных можно удобно создавать с помощью terraform. Помимо базы данных Вы также можете создать такие ресурсы как каталог, сервисный account и прочие ресурсы.
Прекрасный пример развертывания инфраструктуры на Yandex cloud сделал Виктор Кузенный, Вы можете найти его тут: https://github.com/kvikuz/sls-web-application
P.S. Обратите внимание! Любой способ инициализации драйвера YDB требует наличия ENV переменных. Если у Вас компьютер на windows, то Вам необходимо поставить один из пакетов мультиплатформенная поддержки ENV переменных. C этой целью я выбрал dotenv. Для его использования необходимо вызвать один раз функцию config (в примере она вызывается в файле examples/utils/ydb-functions.ts).
Если Вы уже пробовали YDB на nodejs, то заметили что предлагается написать, например, interface ISeason, class Season. Если Вы хотите описать опциональное поле, то декоратор надо писать так:
@declareType({ optionalType: { item: { typeId: typePrim } } })
Для упрощения написания декораторов добавил два декоратора для описания обязательных и опциональных полей:
declareTypePrim - для описания обязательных полей
declareTypeNull - для описания опциональных полей
Теперь декораторы можно записать проще:
@declareTypePrim(TypePrim.UINT64)
public id: number;
@declareTypeNull(TypePrim.UTF8) // вместо @declareType({ optionalType: { item: { typeId: TypePrim.UTF8 } } })
public title?: string;
Если раньше вместе с классом было необходимо написать интерфейс аналогичного содержания, то теперь я добавил generic тип ITableFromClass для получения типа-интерфейса для использования в методе create. Теперь interface не надо описывать самостоятельно.
type ITMdb = ITableFromClass<Tmdb>;
// Метод create теперь выглядит вот так:
static create(inp: ITMdb) {
return new Tmdb(inp);
}
Пример можно посмотреть в файле table_defs.ts
Писать код для создания таблицы, создания интерфейса, запросы YQL для добавления данных несколько утомительно, поэтому я решил пойти дальше.
В одном из issue я предлагал реализовать кодогенерацию, но в итоге решил сделать в базовом классе возможность работы со всем спектром операций с таблицей - создание и удаление таблицы, вставка данных. Наверно имеет смысл добавить Delete одного элемента по набору полей из primary key.
Текущая реализация позволяет с легкостью выполнять все вышеперечисленные действия:
- создать/удалить таблицу согласно сформированному описанию таблицы
- добавить одну строку с данными в таблицу, с возможностью использования опциональных полей (не указывать значения опциональных полей).
- добавить несколько записей в таблицу (все непереданные поля автоматически устанавливаются в null, необходимо заполнять только обязательные поля)
- В будущем добавлю реализацию команды bulk upsert для класса - но у нее есть особенности - она не работает с таблицами у которых есть вторичные индексы.
Нужно выполнить 3 простых шага:
- сформировать объект описания таблицы
- написать строчку для формирования типа - интерфейса (авто вывод типа из объекта-описания таблицы)
- Вызвать static метод класса initTableDef
Для использования новой системы описания таблицы YDB необходимо создать объект вида:
const tdef = {
id: { val: 0, pt: Pt.UINT64, opt: 'r', pk: true },
title: { val: 'title', pt: Pt.UTF8, opt: 0 },
};
Сам объект представляет собой структуру со следующими полями:
Описание | |
---|---|
val | тип столбца YDB в JS. для отображения полей из YDB в JS возможно использование только следующих типов: number, string, BigInt. JSON в YDB отображается на string в JS Поскольку я не могу использовать фактические типы (иначе не получается вывести тип), то вместо типа необходимо задать любое значение Например 0 - это number (вы можете поставить любое число, например 1.25) 'title' - это string |
pt | PrimitiveTypeId - тип столбца в YDB - могут использоваться только определенные значения из enum PrimitiveTypeId (не все из них). Например нельзя указать тип INT8 Список типов, которые можно использовать для типизации столбца указан в документации здесь |
opt | optional - нужно указывать либо 'r' - required либо 0. При автоматическом выводе типа из этого столбца извлекается информация о его типе - string или number |
pk | primary key - это единственно не обязательное поле. Может принимать только одно значение - true. Указание данного значения означает что поле входит в состав primary key таблицы. |
-
Тип DyNumber в YDB использовать в настоящий момент не рекомендуется.
-
Вы можете пользоваться типом Decimal(22,9) который отображается на JS тип BigInt, если точнее то он хранит 64bit целое число.
Внимание!
Объект-константу описания таблицы нельзя типизировать с помощью TS потому что он используется для автоматического выведения типа на основе этого объекта и при типизации этого объекта пропадает возможность вывода типа.
export type ITdef = ConvertStructToTypes<typeof episode>;
(см. пример)
Для осуществления начальной инициализации refMetaData с описанием таблицы YDB, необходимо обязательно вызывать метод initTableDef после определения класса.
Вызов метода initTableDef приводит к формированию необходимых метаданных для таблицы, формированию строк YQL запросов. Вызов этого метода необходим так как у каждого класса (таблицы) свой static объект refMetaData с описанием таблицы YDB.
Пример вызова:
Episodes.initTableDef(databaseName, 'episodes', episode);
Где:
Параметр | Описание |
---|---|
Episodes | название класса в котором Вы описали таблицу |
'episodes' | название таблицы в базе данных YDB |
databaseName | значение, ранее сохраненное в поле DATABASENAME (например "/ru-central1/b1gib03pgvqrrfvhl3kb/etnn9li53arnjigll14s") |
episode | объект, описывающий структуру таблицы |
Оригинальная версия SDK разработана с учетом сохранения метаинформации о типах данных с использованием Reflect.metadata для свойств класса.
Я решил хранить метаданные, описывающие структуру таблицы (они несколько другие по сравнению с оригинальной SDK) в static свойстве (объекте) refMetaData. Такой подход позволяет легко обращаться к метаданным, перебирать ключи метаданных, запускать forEach и другие полезные методы. Реализация static в JS позволяет обращаться к static свойствам и методам наследующего класса из базового класса, что позволило внедрить в базовый класс TypedDataDef все необходимые методы для построения YQL на основе метаданных и методов работы с базой.
Ранее в документации были описаны три понятия: драйвер, клиент, сессия.
Для взаимодействия с YDB необходимо создать экземпляр драйвера, клиента и сессии:
Драйвер YDB отвечает за взаимодействие приложения и YDB на транспортном уровне. Драйвер должен существовать на всем протяжении жизненного цикла работы с YDB. Перед началом работы, необходимо инициализировать драйвер YDB.
В настоящем примере инициализация драйвера осуществляется функцией initYDBdriver (examples/type-utils/ydb-functions.ts).
Для подключения к базе данных необходимо передать авторизационную информацию. Это можно сделать несколькими способами. Все возможные способы описаны в исходном коде SDK. Все способы подразумевает определение той или иной ENV переменной.
Обратите внимание, что часть способов уже deprecated.
Я выбрал наиболее простой способ авторизации в YDB - создал файл с ключами и дал ссылку на него в env.local переменной
YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS
Создание файла с ключами описано в секции "Формирование ключа для доступа к YDB".
При создании драйвера также инициализируется логер. Поскольку проект учебный - то в env.local добавлена переменная которая выводит максимум отладочной информации: YDB_SDK_LOGLEVEL=debug
Клиент отвечает за работу с сущностями YDB.
Самостоятельно клиент создавать не требуется (верно для nodejs SDK) - клиент создается самим драйвером в момент инициализации драйвера.
Драйвер инициализирует DiscoveryService, который опрашивает эндпойнты и связывает с каждым эндпойнтом фабрику сессий.
В рамках драйвера создаются tableClient и schemeClient, основная причина их разделения - это разные пулы сессий.
У каждого пула свой список используемых и свободных сессий, свои min/max-лимиты. При порождении новой сессии в рамках пула (сессия порождается, если все имеющиеся сессии заняты, но мы еще не вышли за пределы max-лимита на данный пул) по очереди обходятся все известные эндпойнты которые нам вернул DiscoveryService, т.е. запрос 1 на порождение сессии получит ее из эндпойнта1, а запрос 2 получит новую сессию из эндпойнта 2 - это простейший механизм балансировки сессий.
Сессия содержит информацию о выполняемых транзакциях, подготовленных запросах и служит средой для выполнения запросов.
Получать сессию необходимо через клиента путем вызова метода
driver.tableClient.withSession
либо
driver.tableClient.withSessionRetry
Единственное отличие этих методов - это параметр maxRetries, который присутствует во втором методе.
При наличии параметра maxRetries служебный метод _withSession пробует исполнить запрос еще раз не более maxRetries раз с другой сессией.
Следует отметить, что автор SDK - Timur Sufiev использует первый способ - withSession. При этом вызов самого запроса оборачивает в withRetries.
При создании базы YDB (или потом) может быть установлено ограничение по пропускной способности, RU/с, которое ограничивает максимальное начисление платы за пользование serverless YDB за 1 секунду. В случае большой нагрузки на YDB при обработке запроса может прийти отказ базы из-за превышения лимита начисления. Также возможны проблемы с сетью из за которых может прерваться соединение и т.д.
Поскольку это стандартная ситуация - то предусмотрены механизмы повторения исполнения отправленного запроса.
withSessionRetry повторяет запрос только при получении двух ошибок: BadSession и SessionBusy.
Второй способ сделать повтор запроса - обернуть метод класса в декоратор @retryable
Третий способ повторения запроса - использование функции-обертки withRetries.
withRetries формирует необходимые параметры и вызывает метод RetryStrategy.retry.
RetryStrategy.retry не пересоздает сессию в случае ошибок RetryStrategy.retry делает ретраи на errors.Unavailable, errors.Aborted, errors.NotFound и errors.Overloaded
В случае если Вы установили лимит на нагрузку БД (например установив ограничение RU/сек) то возможна перегрузка БД запросами. В этом случае будет формироваться исключение errors.Overloaded. В этом случае повтор происходит с увеличенным экспоненциальным таймаутом (см. исходники по RETRYABLE_ERRORS_SLOW).
В процессе обработки запросов Вы можете передавать в executeQuery ряд параметров, связанных с таймаутами.
Более подробно про таймауты Вы можете прочитать в документации
Примеры авторизации Вы можете посмотреть в examples. Возможные варианты авторизации описаны далее:
Данный метод использован практически для всех имеющихся здесь примеров (за исключением auth).
Предлагаемый метод отличается от авторизации по IAM токену тем, что авторизованный ключ сервисного аккаунта не имеет конечного срока действия в отличие от IAM токена, срок действия которого составляет 12 часов.
Более подробно прочитайте тут
Это один из основных методов авторизации.
IAM-токен — уникальная последовательность символов, которая выдается пользователю после прохождения аутентификации. С помощью этого токена пользователь авторизуется в API Yandex.Cloud и выполняет операции с ресурсами.
yc iam create-token
Сохраните полученный токен в файл iam-token.txt в директории examples/auth/access-token-credentials/iam-token.txt
Время жизни IAM-токена не более 12 часов.
Проверьте корректность авторизации, запросив информацию о пользователе:
ydb \
--endpoint ydb.serverless.yandexcloud.net:2135 \
--database /ru-central1/b1gib03pgvqrrfvhl3kb/etnn9li53arnjigll14s \
--iam-token-file iam-token.txt \
discovery whoami \
--groups
Авторизация в YDB CLI (см. вкладку Сервис метаданных)
Сервис метаданных работает на виртуальных машинах внутри Yandex compute cloud, а также в serverless функциях Yandex
Установите переменную YDB_ANONYMOUS_CREDENTIALS='1' в env.local
Анонимная авторизация используется только при локальной отладке либо при запуске запросов из VM на которой установлен YDB. Также она применяется для запросов к YDB, развернутой в Docker.
Для получения сессии для работы с данными предназначены методы SDK withSession и withSessionRetry.
Сессия содержит информацию о выполняемых транзакциях и подготовленных запросах.
Получать сессию необходимо через клиента путем вызова метода
driver.tableClient.withSession
либо
driver.tableClient.withSessionRetry
Единственное отличие этих методов - это параметр maxRetries, который присутствует во втором методе.
При наличии параметра maxRetries служебный метод _withSession пробует исполнить запрос еще раз не более maxRetries раз с другой сессией.
Следует отметить, что автор SDK - Timur Sufiev использует первый способ - withSession. При этом вызов самого запроса оборачивает в withRetries.
withSession<T>(
callback: SessionCallback<T>,
timeout: number = 0) : : Promise<T>
Метод служит для получения сессии для запроса данных.
Первый параметр - callback, который получает ID созданной сессии.
Пример:
await driver.tableClient.withSession(async (session) => { работа с данными в рамках сессии}
Внутри withSession обращается к пулу сессий для клиента и выбирает из этого пула первую свободную сессию, либо создает новую.
В случае если уже создано maxLimit сессий и timeout >0, то withSession запускает таймер со значением timeout. Если до истечения таймаута не находится свободной сессии, то возвращается reject.
Вы можете вернуть внутри callback некие данные типа T, которые в свою очередь вернет withSession по завершении сессии.
withSessionRetry<T>(
callback: SessionCallback<T>,
timeout: number = 0,
maxRetries = 10): Promise<T>
Параметры и предназначение метода полностью аналогичны методу withSession.
Дополнительно withSessionRetry обрабатывает ошибки BadSession и SessionBusy в случае их возникновения предпринимается попытка создать новую сессию.
В случае, если в процессе исполнения запросов внутри сессии произошла ошибка, BadSession или SessionBusy, то создается новая сессия и производится попытка опять повторить выполнение callback целиком. Все это происходит не более maxRetries раз (по умолчанию задано значение 10)
withRetries<T>(
originalFunction: () => Promise<T>,
strategyParams?: RetryParameters)
Функция принимает в качестве параметра функцию, внутри которой идет работа с данными и вторым параметром передаются параметры для стратегии повторов при ошибке.
Параметры для создания стратегии повторов:
Параметр | Описание |
---|---|
maxRetries | По умолчанию 10 - максимальное количество повторов |
onYdbErrorCb | функция callback, которая вызывается при возникновении ошибки и принимает один параметр типа YdbError |
backoffCeiling | параметры для стратегии экспоненциального ретрая. максимальное значение экспоненты по умолчанию 6 |
backoffSlotDuration | значение в миллисекундах, на которое умножается экспоненциальный коэффициент. по умолчанию 1000 |
При ошибке errors.Overloaded включается стратегия экспоненциального ожидания повтора в которой применяются параметры backoffCeiling, backoffSlotDuration. При первом повторе процесс засыпает и ждет backoffSlotDuration миллисекундах, при втором повторе ожидание составит 2*backoffSlotDuration
. Каждая последующая попытка повтора умножает это время на 2 до тех пор пока не будет backoffCeiling повторов. После этого время уже не увеличивается.
withRetries обрабатывает ошибки, описанные в классе YdbError и пытается повторить выполнение запросов не более maxRetries раз.
Вместо применения обертки withRetries Вы можете применить декоратор retryable того же назначения.
public async executeQuery(
query: PrepareQueryResult | string,
params: IQueryParams = {},
txControl: IExistingTransaction | INewTransaction = AUTO_TX,
operationParams?: IOperationParams,
settings?: ExecDataQuerySettings,
collectStats: Ydb.Table.QueryStatsCollection.Mode | null = null
Это основной метод для работы с данными.
Параметр | Описание |
---|---|
query | может представлять как запрос, подготовленный с помощью prepareQuery, так и обычный запрос YQL в строковом формате. |
params | В запросе YQL Вы можете определить что в него будут передаваться фактические параметры. В этот аргумент передается объект в ключах которого указывается имя параметра, определенного в запросе YQL, например $seriesData, передаваемое значение зависит от описания типа в YQL |
txControl | Параметр для контроля за транзакциями. Более подробно будет описано ниже |
operationParams | описание смотри ниже |
settings | При необходимости можно установить в значение {keepInCache: true}. Более подробно параметр описан ниже. |
collectStats | если Вам необходимо узнать сколько записей прочитано (пропорционально этому показателю начисляется плата за запрос RU) - то передайте значение STATS_COLLECTION_BASIC или STATS_COLLECTION_FULL |
В объект operationParams входят следующие показатели:
Параметр | Описание |
---|---|
operationMode | всегда устанавливается в null |
operationTimeout | Таймаут на операцию Значение operation_timeout определяет время, в течение которого результат запроса интересен пользователю. Если за данное время операция не выполнилась, сервер возвращает ошибку c кодом Timeout и попытается прекратить выполнение запроса, однако отмена запроса не гарантируется. Таким образом, запрос, на который пользователю была возвращена ошибка Timeout, может быть как успешно выполнен на сервере, так и отменен |
cancelAfter | Таймаут отмены операции Значение cancel_after определяет время, через которое сервер начнет отмену запроса, если отменить запрос возможно. В случае успешной отмены запроса сервер вернет ошибку с кодом Cancelled. |
labels | Метки, определенные пользователем Представляют из себя обычный объект JS со значениями string В настоящий момент не используется |
reportCostInfo | в настоящий момент не используется |
Примечание: Значения таймаутов может устанавливаться либо в секундах, либо в наносекундах Пример (в обоих случаях задан таймаут 3 секунды):
operationTimeout : {seconds: 3}
или
operationTimeout : {nanos: 3e9}
Параметр settings
У этого параметра может быть только одно установленное значение {keepInCache: true}
В этом случае значение переданное в параметре query сохраняется в кеше на стороне сервера. Фактически происходит синтаксический разбор запроса и из него формируется preparedQuery, ID которого возвращается после выполнения запроса.
Количество возможных мест хранения в кеше ограничено, устаревшие значения выталкиваются из кеша по алгоритму Least recently used (LRU).
Не рекомендуется сохранять в кеше подготовленные запросы.
После выполнения запроса при установленном ключе {keepInCache: true} Вы получите ID preparedQuery в возвращаемых данных в ключе queryMeta.id
ID подготовленного запроса будет выглядеть так: "ydb://preparedqueryid/4?id=9ccafa6-945df2a2-e53d1813-e3772c42"
Далее Вы можете использовать этот ID в следующем запросе
Параметр txControl - параметры транзакций и возможные варианты.
- Можно передать в executeQuery заранее созданную транзакцию с помощью метода beginTransaction. (полный пример доступен тут)
метод beginTransaction возвращает ID транзакции, который можно определить так:
{ txId: transaction.id }
По окончании запроса транзакцию необходимо самостоятельно закомитить либо откатить. Для этого используются методы commitTransaction и rollbackTransaction.
- Для одиночного запроса можно инициировать транзакцию и сразу ее закомитить.
В этом случае параметр будет выглядеть так (использован helper fillTransactionSettings из настоящего пакета):
{ beginTx: fillTransactionSettings('serializableReadWrite'), commitTx: true }
Всего возможно три вида транзакций
- Serializable
- Online Read-Only
- Stale Read Only
Более подробно Вы можете почитать в документации
Хелпер fillTransactionSettings возвращает правильно заполненный объект для передачи в YDB. Вы должны выбрать один из желаемых видов транзакции. Для типа транзакции onlineReadOnly Вы также можете передать параметр allowInconsistentReads.
- Вы можете инициировать создание транзакции в первом запросе executeQuery и завершить транзакцию в последнем запросе. Полный пример смотрите тут
В первом запросе Вы должны открыть транзакцию - но не комитить ее по завершении запроса
{ beginTx: fillTransactionSettings('serializableReadWrite'), commitTx: false }
Во второй и последующие запросы Вы должны передавать transaction ID полученный после выполенения первого запроса
{ txId: data.txMeta.id, commitTx: false }
И, наконец, в последнем запросе Вы должны завершить транзакцию - либо явно в самом конце вызвать метод commitTransaction
{ txId: data.txMeta.id, commitTx: true }
В большинстве случаев вместо явного открытия транзакции с помощью beginTransaction и последующего commitTransaction лучше использовать параметры контроля транзакций в вызовах executeQuery. Это позволит избежать лишних обращений к YDB и эффективней выполнять запросы. (экономится два обращения к базе)
В то же время для улучшения читаемости кода для не сильно нагруженных приложений возможно имеет смысл явно указать beginTransaction/ commitTransaction
Помните, что если Вам нужно сделать несколько запросов к базе (например выполнить запись в несколько таблиц) - то практически всегда Вы сможете записать Ваши запросы в одном YQL предложении с параметрами что позволит обойтись всего одним обращением к YDB.
Служит для подготовки запросов до передачи их методу executeQuery
Если у Вас один запрос выполняется несколько раз с разными данными, то настоятельно рекомендуется использовать только параметризованные запросы. Это позволяет БД выполнить подготовительную работу по разбору и оптимизации запроса только один раз.
public async prepareQuery(
queryText: string,
operationParams?: IOperationParams): Promise<PrepareQueryResult>
Параметр | Описание |
---|---|
queryText | строка запроса YQL включая возможные параметры |
operationParams | см. описание параметра в executeQuery |
Массовая дешевая вставка данных. Плата за вставку данных с помощью bulkUpsert будет несколько ниже.
async bulkUpsert(
table: string,
rows: TypedValue,
operationParams?: IOperationParams)
Параметр | Описание |
---|---|
table | полное имя таблицы вида "/ru-central1/b1gib03pgvqrrfvhl3kb/etnn9li53arnjigll14s/series" - т.е. databaseName + имя таблицы включая все необходимые пути |
operationParams | см. описание параметра в executeQuery |
rows | массив данных для записи, обычно формируемый static методом asTypedCollection в который передается массив объектов класса, например [Series ...] |
Внимание! bulkUpsert не работает с таблицами у которых есть вторичные индексы.
начать новую транзакцию
beginTransaction(
txSettings: ITransactionSettings,
operationParams?: IOperationParams)
Параметр | Описание |
---|---|
txSettings | сюда Вы должны передать тип транзакции - один из serializableReadWrite ,onlineReadOnly, staleReadOnly. Проще всего передать тип транзакции с помощью функции-хелпера fillTransactionSettings |
operationParams | сюда можно передать граничные значения таймаутов Это проще сделать с помощью функции-хелпера fillTimeOuts |
завершить транзакцию и записать изменения в базу данных
commitTransaction(
txControl: IExistingTransaction,
operationParams?: IOperationParams)
Параметр | Описание |
---|---|
txSettings | сюда Вы должны передать ID существующей транзакции в виде объекта {txId : string} |
operationParams | сюда можно передать граничные значения таймаутов Это проще сделать с помощью функции-хелпера fillTimeOuts |
откатить все изменения в рамках существующей транзакции
rollbackTransaction(
txControl: IExistingTransaction,
operationParams?: IOperationParams)
Параметр | Описание |
---|---|
txSettings | сюда Вы должны передать ID существующей транзакции в виде объекта {txId : string} |
operationParams | сюда можно передать граничные значения таймаутов Это проще сделать с помощью функции-хелпера fillTimeOuts |
Результатом выполнения скан запроса является автоматическое выполнение запроса сервером с последующим вызовом callback при поступлении данных от сервера.
async streamExecuteScanQuery(
query: PrepareQueryResult | string,
consumer: (result: ExecuteScanQueryPartialResult) => void,
params: IQueryParams = {},
settings?: ExecuteScanQuerySettings)
Параметр | Описание |
---|---|
query | может представлять как запрос, подготовленный с помощью prepareQuery, так и обычный запрос YQL в string |
params | В запросе YQL Вы можете определить что в него будут передаваться фактические параметры. В этот аргумент передается объект в ключах которого указывается имя параметра, определенного в запросе YQL, например $seriesData, передаваемое значение зависит от описания типа в YQL |
txControl | Параметр для контроля за транзакциями. Например Вы можете передать внешний идентификатор транзакции и потом закрыть транзакцию после выполнения ряда запросов. |
settings | неизвестно - принимает объект с ключом mode: { MODE_UNSPECIFIED ,MODE_EXPLAIN ,MODE_EXEC } |
consumer | функция на вход которой поступает массив частичных значений из запроса и структура со статистикой. Загрузка следующей порции данных производится самим сервером. Чем то напоминает cursor в других SQL серверах |
async streamReadTable(
path: string,
consumer: (result: Ydb.Table.ReadTableResult) => void,
settings?: ReadTableSettings)
Параметр | Описание |
---|---|
path | название таблицы с префиксом - databaseName, может включать в себя длинный путь. Например path может быть такой: "/ru-central1/b1gib03pgvqrrfvhl3kb/etnn9li53arnjigll14s/bulk_upsert/log_messages" здесь bulk_upsert - имя директории log_messages - имя таблицы |
settings | проще всего управлять данным параметром с помощью класса ReadTableSettings Вы можете выбрать какие столбцы вернуть в ответе, указать сколько строк возвращать за один раз, надо ли упорядочить вывод значений (по primary key), также доступно большое количество операций по отбору необходимых значений первичного ключа |
consumer | функция на вход которой поступает массив частичных значений из запроса и структура со статистикой. Переход к следующему chank данных производится самим сервером. Чем то напоминает cursor в других SQL серверах |
Заполняет типы транзакций в YDB-SDK более понятным способом. Данный метод используется при заполнении параметров новой транзакции txControl в методе executeQuery, формирует новую транзакцию.
export type TransactionType = 'serializableReadWrite' | 'onlineReadOnly' | 'staleReadOnly';
fillTransactionSettings(
txType: TransactionType,
allowInconsistentReads?: boolean | null
)
Пример
const data = await session.executeQuery(
"upsert into series (series_id, title) values (11,'11')", // query
{}, // params
{ beginTx: fillTransactionSettings('serializableReadWrite'), commitTx: false }
);
Заполняет параметры таймаутов для транзакций в YDB-SDK более понятным способом
С помощью данного хелпера Вы можете заполнить такие параметры как operationTimeout и cancelAfter параметра operationParams метода executeQuery.
fillTimeOuts(
operationTimeout?: number,
cancelAfter?: number)
Пример
const data = await session.executeQuery(
"upsert into series (series_id, title) values (11,'11')", // query
{}, // params
{ beginTx: fillTransactionSettings('serializableReadWrite'), commitTx: true },
fillTimeOuts(3, 3) // параметры operationMode, labels, reportCostInfo в настоящий момент не используются в SDK, поэтому заполнять их не требуется
);
Для упрощения работы произведено расширение функционала пакета YDB-SDK и добавлены новые сигнатуры функций с более простым заполнением параметров.
начинает транзакцию
beginTransactionQuick(
txType: TransactionType,
allowInconsistentReads?: boolean | null,
operationTimeout?: number,
cancelAfter?: number
)
Параметр | Описание |
---|---|
txType | Передайте значение из типа TransactionType = 'serializableReadWrite' / 'onlineReadOnly' / 'staleReadOnly' для выбора типа транзакции |
allowInconsistentReads | Данные параметр параметр применяется только если Вы выбрали тип транзакции onlineReadOnly false (consistent reads). В данном режиме каждое из чтений по отдельности возвращает консистентные данные, но консистентность данных между разными чтениями не гарантируется. Дважды выполненное чтение одного и того же диапазона таблицы может вернуть разные результаты. true (inconsistent reads). В данном режиме данные даже для отдельно взятого чтения могут содержать не консистентные результаты. |
operationTimeout | Задается в секундах Значение operation_timeout определяет время, в течение которого результат запроса интересен пользователю. Если за данное время операция не выполнилась, сервер возвращает ошибку c кодом Timeout и попытается прекратить выполнение запроса, однако отмена запроса не гарантируется. Таким образом, запрос, на который пользователю была возвращена ошибка Timeout , может быть как успешно выполнен на сервере, так и отменен. |
cancelAfter | Задается в секундах Значение cancel_after определяет время, через которое сервер начнет отмену запроса, если отменить запрос возможно. В случае успешной отмены запроса сервер вернет ошибку с кодом Cancelled |
выполняет запрос к YDB
executeQueryQuick = async function (
query: Ydb.Table.PrepareQueryResult | string,
params?: IQueryParams,
txControl?: IExistingTransaction | INewTransaction,
timeOuts?: { operationTimeout?: number; cancelAfter?: number },
casheSettings = false,
collectStats?: Ydb.Table.QueryStatsCollection.Mode | null
)
Параметр | Описание |
---|---|
query | может представлять как запрос, подготовленный с помощью prepareQuery, так и обычный запрос YQL в string |
params | В запросе YQL Вы можете определить что в него будут передаваться фактические параметры. В этот аргумент передается объект в ключах которого указывается имя параметра, определенного в запросе YQL, например $seriesData, передаваемое значение зависит от описания типа в YQL |
txControl: IExistingTransaction | Передайте ID существующей транзакции в формате {txId: string} |
txControl: INewTransaction | Передайте параметры новой транзакции в формате { txType: TransactionType; commitTx?: boolean; allowInconsistentReads?: boolean } Более подробно см. в описании параметров beginTransactionQuick |
timeOuts | Таймауты Более подробно см. в описании параметров beginTransactionQuick |
casheSettings | Параметр сохранения запроса сервером в кеше. Более подробно смотри тут |
collectStats | если Вам необходимо узнать сколько записей прочитано (пропорционально этому показателю начисляется плата за запрос RU) - то передайте значение STATS_COLLECTION_BASIC или STATS_COLLECTION_FULL |