Como usar o Armazenamento de Tabelas do Azure e ou o Azure Cosmos DB for Table no Node.js

APLICA-SE AO: Table

Dica

O conteúdo deste artigo se aplica ao Armazenamento de Tabelas do Azure e ao Azure Cosmos DB for Table. A API for Table é uma oferta premium para armazenamento de tabelas que oferece tabelas com taxa de transferência otimizada, distribuição global e índices secundários automáticos.

Este artigo mostra como criar tabelas, armazenar dados e realizar operações CRUD nesses dados. As amostras são escritas em Node.js.

Criar uma conta de serviço do Azure

Você pode trabalhar com tabelas usando o Armazenamento de Tabelas do Azure ou o Azure Cosmos DB. Para saber mais sobre as diferenças entre as ofertas de tabela desses dois serviços, confira a Visão geral da API para tabela. Você precisará criar uma conta para o serviço que pretende usar. As seções a seguir mostram como criar as contas do Armazenamento de Tabelas do Azure e do Azure Cosmos DB, no entanto, você pode usar apenas um deles.

Crie uma conta de armazenamento do Azure

A maneira mais fácil de criar uma conta de armazenamento do Azure é usando o portal do Azure. Para saber mais, consulte Criar uma conta de armazenamento.

Você também pode criar uma conta de armazenamento do Azure usando o Azure PowerShell ou a CLI do Azure.

Se você preferir não criar uma conta de armazenamento no momento, também poderá usar o Emulador de Armazenamento do Azure para executar e testar o seu código em um ambiente local. Para saber mais, confira Usar o Emulador de Armazenamento do Azure para desenvolvimento e teste.

Criar uma conta do Azure Cosmos DB for Table

Para obter instruções sobre como criar uma conta do Azure Cosmos DB for Table, veja Criar uma conta de banco de dados.

Configurar o aplicativo para acessar o Armazenamento de Tabelas

Para usar o Armazenamento do Microsoft Azure ou o Azure Cosmos DB, você precisa do SDK das Tabelas do Azure para Node.js, que inclui um conjunto de bibliotecas de conveniência que comunicam-se com os serviços REST de Armazenamento.

Usar o NPM (Gerenciador de Pacotes de Nós) para obter o pacote

  1. Use uma interface de linha de comando, como PowerShell (Windows), Terminal (Mac) ou Bash (Unix), e navegue até a pasta em que você criou o aplicativo.
  2. Digite o seguinte na janela de comando:
   npm install @azure/data-tables
  1. Você pode executar manualmente o comando ls para verificar se uma pasta node_modules foi criada. Dentro dessa pasta, você encontrará o pacote @azure/data-tables que contém as bibliotecas necessárias para acessar as tabelas.

Importar o pacote

Adicione o código a seguir à parte superior do arquivo server.js em seu aplicativo:

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

Conectar-se ao serviço Tabela do Azure

Você pode se conectar à conta de armazenamento do Azure ou à conta do Azure Cosmos DB for Table. Obtenha a cadeia de conexão ou a chave compartilhada com base no tipo de conta que você está usando.

Como criar o cliente de serviço Tabela com base em uma chave compartilhada

O módulo do Azure lê as variáveis de ambiente AZURE_ACCOUNT and AZURE_ACCESS_KEY e AZURE_TABLES_ENDPOINT para obter as informações necessárias para se conectar à conta de Armazenamento do Azure ou ao Azure Cosmos DB. Se essas variáveis de ambiente não estiverem definidas, você deverá especificar as informações da conta ao chamar TableServiceClient. Por exemplo, o seguinte código cria um objeto TableServiceClient:

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

const tableService = new TableServiceClient(
  endpoint,
  credential
);

Como criar o cliente de serviço Tabela por meio de uma cadeia de conexão

Para adicionar uma conexão da conta de Armazenamento ou do Azure Cosmos DB, crie um objeto TableServiceClient e especifique o nome da conta, a chave primária e o ponto de extremidade. Copie esses valores em Configurações>Cadeia de Conexão no portal do Azure da conta de Armazenamento do Azure ou Azure Cosmos DB. Por exemplo:

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

Criar uma tabela

A chamada para createTable criará uma tabela com o nome especificado, se ela ainda não existir. O exemplo a seguir criará uma nova tabela denominada 'mytable' se ele ainda não existir:

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

Criar o cliente de tabela

Para interagir com uma tabela, crie um objeto TableClient usando as mesmas credenciais que foram usadas para criar TableServiceClient. O nome da tabela de destino também é necessário para TableClient.

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

Adicionar uma entidade a uma tabela

Para adicionar uma entidade, primeiro crie um objeto que defina as propriedades da entidade. Todas as entidades devem conter uma partitionKey e rowKey, que são identificadores exclusivos da entidade.

  • partitionKey – Determina a partição na qual a entidade está armazenada.
  • rowKey – identifica exclusivamente a entidade dentro da partição.

Ambas, partitionKey e rowKey, devem ser valores de cadeia de caracteres.

A seguir, um exemplo de definição de uma entidade. O dueDate é definido como um tipo de Date. A especificação do tipo é opcional, e os tipos são inferidos, se não forem especificados.

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

Observação

Existe também um campo Timestamp para cada registro, que é definido pelo Azure quando uma entidade é inserida ou atualizada.

Para adicionar uma entidade à sua tabela, passe o objeto de entidade para o método createEntity.

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

Se a operação for realizada com sucesso, result conterá a Etag e as informações sobre a operação.

Resposta de exemplo:

{ 
  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'
}

Atualizar uma entidade

Os diferentes modos para os métodos updateEntity e upsertEntity

  • Mesclar: atualiza uma entidade atualizando as propriedades da entidade sem substituir a entidade existente.
  • Substituir: atualiza uma entidade existente substituindo toda a entidade.

O seguinte exemplo demonstra a atualização de uma entidade usando upsertEntity:

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

Se a entidade que está sendo atualizada não existir, a operação de atualização falhará. Portanto, se você quiser armazenar uma entidade independentemente de sua existência, use upsertEntity.

O result de operações de atualização bem-sucedidas conterá o Etag da entidade atualizada.

Trabalhar com grupos de entidades

Às vezes, convém enviar várias operações juntas em um lote para garantir o processamento atômico pelo servidor. Para fazer isso, crie uma matriz de operações e passe-a para o método submitTransaction em TableClient.

O exemplo a seguir demonstra o envio de duas entidades em um lote:

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

Para operações em lote bem-sucedidas, result conterá informações para cada operação no lote.

Recuperar uma entidade por chave

Para retornar uma entidade específica com base em PartitionKey e RowKey, use o método getEntity.

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

Quando essa operação for concluída, result conterá a entidade.

Consultar um conjunto de entidades

O exemplo a seguir compila uma consulta que retorna os cinco principais itens com uma PartitionKey de "hometasks" e lista todas as entidades na tabela.

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);
}

consultar um subconjunto de propriedades da entidade

Uma consulta a uma tabela pode recuperar apenas alguns campos de uma entidade. Isso reduz a largura de banda e pode melhorar o desempenho da consulta, principalmente em grandes entidades. Use a cláusula select e transmita os nomes dos campos a serem retornados. Por exemplo, a consulta a seguir retorna apenas os campos description e 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;
}

Excluir uma entidade

Você pode excluir uma entidade usando suas chaves de partição e de linha. Neste exemplo, o objeto task1 contém os valores rowKey e partitionKey da entidade a ser excluída. Depois o objeto é passado para o método deleteEntity .

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

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

Observação

Considere o uso de ETags ao excluir itens, para garantir que o item não seja modificado por outro processo. Veja Atualizar uma entidade para obter informações sobre o uso de ETags.

Excluir uma tabela

O código a seguir exclui uma tabela de uma conta de armazenamento.

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

Usar tokens de continuação

Quando você estiver consultando tabelas com grandes quantidades de resultados, deverá procurar tokens de continuação. Pode haver grandes quantidades de dados disponíveis para a sua consulta dos quais talvez você não saiba, se não criá-la de modo a reconhecer quando um token de continuação está presente.

O objeto results retornado durante a consulta de entidades define uma propriedade continuationToken quando esse token está presente. Você pode usar isso ao realizar uma consulta para continuar a mover-se pela partição e entidades de tabela.

Ao consultar, é possível fornecer um parâmetro continuationToken entre a instância do objeto de consulta e a função de retorno de chamada:

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);
   }
 }

Trabalhar com assinaturas de acesso compartilhado

SAS (Assinaturas de acesso compartilhado) são uma maneira segura de fornecer acesso granular a tabelas sem fornecer o nome ou as chaves da conta de Armazenamento. As SAS são muitas vezes usadas para fornecer acesso limitado aos seus dados, como permitir que um aplicativo móvel consulte registros.

Um aplicativo confiável, como um serviço baseado em nuvem, gera uma SAS usando o generateTableSas do TableClient e a fornece a um aplicativo não confiável ou semiconfiável, como um aplicativo móvel. A SAS é gerada utilizando uma política que descreve as datas inicial e final durante as quais a SAS é válida, assim como o nível de acesso concedido ao titular da SAS.

O exemplo a seguir gera uma nova política de acesso compartilhado, que permitirá que o proprietário da SAS consulte ('r') a tabela.

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
});

O aplicativo cliente usa a SAS com AzureSASCredential para executar operações na tabela. O exemplo a seguir conecta à tabela e executa uma consulta. Confira o artigo Conceder acesso limitado a recursos de Armazenamento do Azure usando SAS (assinaturas de acesso compartilhado) sobre o formato de tableSAS.

// 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}` }
});

Como a SAS foi gerada só com acesso de consulta, se você tentar inserir, atualizar ou excluir entidades, surgirá um erro.

Listas de Controle de Acesso

Você também pode usar uma ACL (Lista de Controle de Acesso) para definir a política de acesso para uma SAS. Isso é útil se você quiser permitir que vários clientes acessem a tabela, mas oferecem diferentes políticas de acesso para cada cliente.

Uma ACL é implementada através de um conjunto de políticas de acesso, com uma ID associada a cada política. O seguinte exemplo define duas políticas: uma para “user1” e outra para “user2”:

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

O exemplo a seguir obtém a ACL atual para a tabela hometasks e adiciona as novas políticas usando setAccessPolicy. Essa abordagem permite:

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

Após a definição da ACL, você pode criar uma SAS com base na ID de uma política. O exemplo a seguir cria uma nova SAS para 'user2':

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

Próximas etapas

Para obter mais informações, consulte os recursos a seguir.