Использование хранилища таблиц Azure или Azure Cosmos DB для таблицы из Node.js

Область применения: Таблица

Совет

Содержимое этой статьи относится к хранилищу таблиц Azure и Azure Cosmos DB для таблицы. API для таблицы — это предложение уровня "Премиум" для хранилища таблиц, которое предлагает оптимизированные для пропускной способности таблицы, глобальное распределение и автоматические вторичные индексы.

В этой статье показано, как создавать таблицы, сохранять данные и выполнять операции CRUD с такими данными. Примеры кода написаны на языке Node.js.

Создание учетной записи службы Azure

Вы можете работать с таблицами, используя хранилище таблиц Azure или Azure Cosmos DB. Дополнительные сведения о различиях между предложениями таблиц в этих двух службах см. в обзоре API для таблиц. Для службы, которую вы планируете использовать, потребуется создать учетную запись. В следующих разделах показано, как создать и хранилище таблиц Azure, и учетную запись Azure Cosmos DB, однако можно использовать что-то одно.

Создание учетной записи службы хранилища Azure

Самый простой способ создать учетную запись хранения Azure — воспользоваться порталом Azure. Чтобы узнать больше, см. раздел Создание учетной записи хранилища.

Учетную запись хранения Azure можно создать также с помощью Azure PowerShell или Azure CLI.

Если вы не хотите сейчас создавать учетную запись хранения, код можно запустить и протестировать в локальной среде с помощью эмулятора хранения Azure. Дополнительные сведения см. в статье Использование Эмулятора службы хранилища Azure для разработки и тестирования.

Создание учетной записи Azure Cosmos DB для таблицы

Инструкции по созданию учетной записи Azure Cosmos DB для таблицы см. в статье "Создание учетной записи базы данных".

Настройка приложения для доступа к хранилищу таблиц

Чтобы использовать службу хранилища Azure или Azure Cosmos DB, вам понадобится пакет SDK таблиц Azure для Node.js, который содержит набор вспомогательных библиотек, взаимодействующих со службами REST хранилища.

Использование диспетчера пакета Node (NPM) для установки пакета

  1. Используя интерфейс командной строки, например PowerShell (Windows), Terminal (Mac) или Bash (Unix), перейдите в папку, в которой вы создали приложение.
  2. Введите в окне команд следующее:
   npm install @azure/data-tables
  1. Выполнив команду ls вручную, можно убедиться, что папка node_modules создана. В этой папке находится пакет @azure/data-tables, содержащий библиотеки, необходимые для доступа к таблицам.

Импорт пакета

Добавьте следующий код в начало файла server.js в приложении:

const { TableServiceClient, TableClient, AzureNamedKeyCredential, odata } = require("@azure/data-tables");

Подключение к службе таблиц Azure

Вы можете подключиться к учетной записи хранения Azure или учетной записи Azure Cosmos DB для таблицы. Получите общий ключ или строку подключения на основе типа используемой учетной записи.

Создание клиента службы таблиц на основе общего ключа

Модуль Azure считывает переменные среды AZURE_ACCOUNT и AZURE_ACCESS_KEY и AZURE_TABLES_ENDPOINT для получения сведений, необходимых для подключения к учетной записи служба хранилища Azure или Azure Cosmos DB. Если эти переменные среды не заданы, при вызове TableServiceClient необходимо указать сведения об учетной записи. Например, следующий код создает объект TableServiceClient.

const endpoint = "<table-endpoint-uri>";
const credential = new AzureNamedKeyCredential(
  "<account-name>",
  "<account-key>"
);

const tableService = new TableServiceClient(
  endpoint,
  credential
);

Создание клиента службы таблиц на основе строки подключения

Чтобы добавить подключение к Azure Cosmos DB или к учетной записи хранения, создайте объект TableServiceClient и укажите имя учетной записи, первичный ключ и конечную точку. Эти значения можно скопировать из строки Параметры Подключение ion String в портал Azure> для учетной записи Azure Cosmos DB или служба хранилища учетной записи. Например:

const tableService = TableServiceClient.fromConnectionString("<connection-string>");

Создание таблицы

Вызов createTable создает таблицу с определенным именем, если она еще не существует. В следующем примере создается новая таблица с именем "mytable", если она еще не создана:

await tableService.createTable('<table-name>');

Создание клиента таблицы

Чтобы взаимодействовать с таблицей TableClient , необходимо создать объект, используя те же учетные данные, которые вы использовали для создания TableServiceClient. Для TableClient этого также требуется имя целевой таблицы.

const tableClient = new TableClient(
  endpoint,
  '<table-name>',
  credential
);

Добавление сущности в таблицу

Чтобы добавить сущность, сначала создайте объект, который определяет свойства сущности. Все сущности должны содержать ключи partitionKey и rowKey, которые выступают уникальными идентификаторами для сущности.

  • partitionKey — определяет раздел, в котором хранится сущность.
  • rowKey — уникально определяет сущность в разделе.

partitionKey и rowKey должны быть строковыми значениями.

Ниже приводится пример задания сущности. Параметр dueDate определяется как тип Date. Задание типа необязательно, типы будут выведены, если они не заданы.

const task = {
  partitionKey: "hometasks",
  rowKey: "1",
  description: "take out the trash",
  dueDate: new Date(2015, 6, 20)
};

Примечание.

Для каждой записи есть поле Timestamp, значение которого задается Azure при вставке или обновлении сущности.

Чтобы добавить сущность в таблицу, передайте объект сущности в метод createEntity.

let result = await tableClient.createEntity(task);
    // Entity create

Если операция выполнена успешно, result содержит ETag и сведения об операции.

Пример ответа:

{ 
  clientRequestId: '94d8e2aa-5e02-47e7-830c-258e050c4c63',
  requestId: '08963b85-1002-001b-6d8c-12ae5d000000',
  version: '2019-02-02',
  date: 2022-01-26T08:12:32.000Z,
  etag: `W/"datetime'2022-01-26T08%3A12%3A33.0180348Z'"`,
  preferenceApplied: 'return-no-content',
  'cache-control': 'no-cache',
  'content-length': '0'
}

Обновление сущности

Различные режимы для методов updateEntity и upsertEntity

  • Слияние. Данная операция обновляет сущность путем обновления ее свойств без замены существующей сущности.
  • Замена. Данная операция обновляет существующую сущность, заменяя всю сущность.

В следующем примере показано обновление сущности с помощью метода upsertEntity.

// Entity doesn't exist in table, so calling upsertEntity will simply insert the entity.
let result = await tableClient.upsertEntity(task, "Replace");

Если сущность, которая обновляется, не существует, то произойдет сбой операции обновления. Таким образом, если вы хотите сохранить сущность независимо от того, существует она уже или нет, используйте upsertEntity.

result содержит значение Etag обновленной сущности в случае успешного выполнения операций.

Работа с группами сущностей

Иногда имеет смысл отправлять совместно несколько операций в пакете для атомарной обработки сервером. Для этого создайте массив операций и передайте его в метод submitTransaction в TableClient.

В следующем примере показана отправка двух сущностей в пакете:

const task1 = {
  partitionKey: "hometasks",
  rowKey: "1",
  description: "Take out the trash",
  dueDate: new Date(2015, 6, 20)
};
const task2 = {
  partitionKey: "hometasks",
  rowKey: "2",
  description: "Wash the dishes",
  dueDate: new Date(2015, 6, 20)
};

const tableActions = [
  ["create", task1],
  ["create", task2]
];

let result = await tableClient.submitTransaction(tableActions);
    // Batch completed

В успешных пакетных операциях result содержит информацию о всех операциях в пакете.

Получение сущности по ключу

Чтобы получить конкретную сущность на основе ключей PartitionKey и RowKey, используйте метод getEntity.

let result = await tableClient.getEntity("hometasks", "1")
  .catch((error) => {
    // handle any errors
  });
  // result contains the entity

После завершения этой операции result будет содержать сущность.

Запрос набора сущностей

В следующем примере создается запрос, который возвращает первые пять элементов с ключом PartitionKey со значением «hometasks» и списком всех сущностей в таблице.

const topN = 5;
const partitionKey = "hometasks";

const entities = tableClient.listEntities({
  queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` }
});

let topEntities = [];
const iterator = entities.byPage({ maxPageSize: topN });

for await (const page of iterator) {
  topEntities = page;
  break;
}

// Top entities: 5
console.log(`Top entities: ${topEntities.length}`);

// List all the entities in the table
for await (const entity of entities) {
console.log(entity);
}

Запрос подмножества свойств сущности

Запрос к таблице может получить лишь несколько полей сущности. Этот позволяет снизить потребление пропускной способности и может повысить производительность запросов, особенно для крупных сущностей. С помощью предложения select передайте имена возвращаемых полей. Например, следующий запрос возвратит только поля description и dueDate.

const topN = 5;
const partitionKey = "hometasks";

const entities = tableClient.listEntities({
  queryOptions: { filter: odata`PartitionKey eq ${partitionKey}`,
                  select: ["description", "dueDate"]  }
});

let topEntities = [];
const iterator = entities.byPage({ maxPageSize: topN });

for await (const page of iterator) {
  topEntities = page;
  break;
}

Удаление сущности

Сущность можно удалить с помощью ее ключей раздела и строки. В этом примере объект task1 содержит значения ключей rowKey и partitionKey удаляемой сущности. Затем этот объект передается в метод deleteEntity .

const tableClient = new TableClient(
  tablesEndpoint,
  tableName,
  new AzureNamedKeyCredential("<accountName>", "<accountKey>")
);

await tableClient.deleteEntity("hometasks", "1");
    // Entity deleted

Примечание.

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

Удалить таблицу

Следующий код удаляет таблицу из учетной записи хранения.

await tableClient.deleteTable(mytable);
        // Table deleted

Использование маркеров продолжения

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

При наличии такого маркера объект results, возвращаемый при запросе сущностей, задает свойство continuationToken. В последствии его можно использовать при выполнении запроса для продолжения и перемещения между разделами и сущностями таблицы.

При выполнении запросов для экземпляра объекта запроса и функции обратного вызова можно указать параметр continuationToken.

let iterator = tableClient.listEntities().byPage({ maxPageSize: 2 });
let interestingPage;

const page = await tableClient
   .listEntities()
   .byPage({ maxPageSize: 2, continuationToken: interestingPage })
   .next();

 if (!page.done) {
   for (const entity of page.value) {
     console.log(entity.rowKey);
   }
 }

Работа с подписями общего доступа

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

Доверенное приложение, например облачная служба, создает подписанный URL-адрес с помощью метода generateTableSas из TableClient и передает его недоверенному или полудоверенному приложению, например мобильному приложению. Подпись SAS создается с использованием политики, которая описывает даты начала и окончания срока действия SAS, а также уровень доступа, который предоставляется держателю подписи SAS.

В следующем примере создается новая политика общего доступа, которая позволит держателю SAS запрашивать ('r') таблицу.

const tablePermissions = {
    query: true
// Allows querying entities
};

// Create the table SAS token
const tableSAS = generateTableSas('mytable', cred, {
  expiresOn: new Date("2022-12-12"),
  permissions: tablePermissions
});

Клиентское приложение далее использует подпись SAS с помощью AzureSASCredential для выполнения операций с таблицей. Следующий пример выполняет подключение к таблице и выполняет запрос. Дополнительные сведения о формате подписанных URL-адресов для таблиц см. в статье об использование подписанных URL-адресов SAS в службе хранилища Azure.

// Note in the following command, tablesUrl is in the format: `https://<your_storage_account_name>.table.core.windows.net` and the tableSAS is in the format: `sv=2018-03-28&si=saspolicy&tn=mytable&sig=9aCzs76n0E7y5BpEi2GvsSv433BZa22leDOZXX%2BXXIU%3D`;

const tableService = new TableServiceClient(tablesUrl, new AzureSASCredential(tableSAS));
const partitionKey = "hometasks";

const entities = tableService.listTables({
  queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` }
});

Так как подписанный URL-адрес был создан только для выполнения запросов, при попытке вставки, обновления или удаления сущностей будет возвращена ошибка.

Списки управления доступом

Можно также использовать список управления доступом (ACL) для задания политики доступа подписи SAS. Это может оказаться удобным, когда необходимо предоставить доступ к таблице нескольким клиентам, но с различной политикой доступа для каждого из них.

ACL реализуется с помощью массива политик доступа, каждая из которых связана со своим идентификатором. В следующем примере определяются две политики, по одной для пользователей user1 и user2:

var sharedAccessPolicy = [{
  id:"user1",
  accessPolicy:{
    permission: "r" ,
    Start: startsOn,
    Expiry: expiresOn,
  }},
  {
  id:"user2",
  accessPolicy:{
    permissions: "a",
    Start: startsOn,
    Expiry: expiresOn,
  }},
]

В этом примере код получает текущий список ACL для таблицы hometasks, а затем добавляет новые политики с помощью setAccessPolicy. Такой подход допускает выполнение:

tableClient.getAccessPolicy();
tableClient.setAccessPolicy(sharedAccessPolicy);

После задания списка управления доступом можно создать подписанный URL-адрес на основе идентификатора политики. В следующем примере создается новая подпись SAS для пользователя 'user2':

tableSAS = generateTableSas("hometasks",cred,{identifier:'user2'});

Следующие шаги

Для получения дополнительных сведений см. следующие ресурсы.