Come usare l'archiviazione tabelle di Azure o Azure Cosmos DB per tabella da Node.js

SI APPLICA A: Tabella

Suggerimento

Il contenuto di questo articolo si applica all'archiviazione tabelle di Azure e ad Azure Cosmos DB per la tabella. L'API per Table è un'offerta Premium per l'archiviazione tabelle che offre tabelle ottimizzate per la velocità effettiva, distribuzione globale e indici secondari automatici.

Questo articolo illustra come creare tabelle, archiviare i dati ed eseguire operazioni CRUD su tali dati. Gli esempi sono scritti in Node.js.

Creare un account del servizio di Azure

È possibile usare le tabelle con l'archiviazione tabelle di Azure o con Azure Cosmos DB. Per altre informazioni sulle differenze tra le offerte di tabelle in questi due servizi, vedere panoramica dell'API per la tabella. Sarà necessario creare un account per il servizio che si intende usare. Le sezioni seguenti illustrano come creare sia l'archiviazione tabelle di Azure che l'account Azure Cosmos DB, tuttavia è possibile scegliere tra uno dei due.

Creare un account di archiviazione di Azure

Il modo più semplice per creare un account di archiviazione di Azure consiste nell'usare il portale di Azure. Per ulteriori informazioni, vedi Creare un account di archiviazione.

È possibile anche creare un account di archiviazione di Azure usando Azure PowerShell o l'interfaccia della riga di comando di Azure.

Se si preferisce non creare un account di archiviazione in questa fase, è anche possibile usare l'emulatore di archiviazione di Azure per eseguire e testare il codice in un ambiente locale. Per altre informazioni, vedere Usare l'emulatore di archiviazione di Azure per sviluppo e test.

Creare un account Azure Cosmos DB per tabelle

Per istruzioni sulla creazione di un account Azure Cosmos DB per tabelle, vedere Creare un account di database.

Configurare l'applicazione per l'accesso a Table Archiviazione

Per usare Archiviazione di Azure o Azure Cosmos DB, è necessario Azure Tables SDK per Node.js, che include un set di librerie utili che comunicano con i servizi REST Archiviazione.

Usare Node Package Manager (NPM) per installare il pacchetto

  1. Usare un'interfaccia della riga di comando come PowerShell (Windows), Terminale (Mac) o Bash (Unix) e passare alla cartella in cui è stata creata l'applicazione.
  2. Digitare quanto segue nella finestra di comando:
   npm install @azure/data-tables
  1. È possibile eseguire manualmente il comando ls per verificare che sia stata creata una cartella node_modules. All'interno di tale cartella è disponibile il pacchetto @azure/data-tables , che contiene le librerie necessarie per accedere alle tabelle.

Importare il pacchetto

Aggiungere il codice seguente all'inizio del file server.js nell'applicazione:

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

Connettersi al servizio tabelle di Azure

È possibile connettersi all'account di archiviazione di Azure o all'account Azure Cosmos DB per tabelle. Ottenere la chiave condivisa o stringa di connessione in base al tipo di account in uso.

Creazione del client del servizio tabelle da una chiave condivisa

Il modulo di Azure legge le variabili di ambiente AZURE_ACCOUNT e AZURE_ACCESS_KEY e AZURE_TABLES_ENDPOINT per informazioni necessarie per connettersi all'account Archiviazione di Azure o ad Azure Cosmos DB. Se queste variabili di ambiente non sono impostate, è necessario specificare le informazioni relative all'account durante la chiamata di TableServiceClient. Il codice seguente, ad esempio, crea un oggetto TableServiceClient:

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

const tableService = new TableServiceClient(
  endpoint,
  credential
);

Creazione del client del servizio tabelle da un stringa di connessione

Per aggiungere una connessione ad Azure Cosmos DB o Archiviazione account, creare un TableServiceClient oggetto e specificare il nome dell'account, la chiave primaria e l'endpoint. È possibile copiare questi valori da Impostazioni> Connessione ion String nel portale di Azure per l'account Azure Cosmos DB o Archiviazione account. Ad esempio:

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

Crea una tabella

La chiamata a createTable crea una nuova tabella con il nome specificato, se non è già presente. Nell'esempio seguente viene creata una nuova tabella denominata "mytable" se questa non esiste ancora:

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

Creazione del client di tabella

Per interagire con una tabella, è necessario creare un TableClient oggetto usando le stesse credenziali usate per creare l'oggetto TableServiceClient. Richiede TableClient anche il nome della tabella di destinazione.

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

Aggiungere un'entità a una tabella

Per aggiungere un'entità, creare prima un oggetto che definisca le proprietà dell'entità. Tutte le entità devono contenere partitionKey e rowKey, che sono identificatori univoci per l'entità.

  • partitionKey : determina la partizione in cui è archiviata l'entità.
  • rowKey : identifica in modo univoco l'entità all'interno della partizione.

Sia partitionKey che rowKey devono essere valori stringa.

Nell'esempio seguente viene definita un'entità. Il valore di dueDate è definito come tipo di Date. La definizione del tipo è facoltativa e i tipi vengono dedotti se non sono specificati.

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

Nota

Per ogni record è anche presente un campo Timestamp, impostato da Azure quando viene inserita o aggiornata un'entità.

Per aggiungere un'entità alla tabella, passare l'oggetto entità al metodo createEntity.

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

Se l'operazione ha esito positivo, result contiene l'ETag e le informazioni sull'operazione.

Esempio di risposta:

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

Aggiornare un'entità

Modalità diverse per updateEntity i metodi e upsertEntity

  • Merge: Aggiornamenti un'entità aggiornando le proprietà dell'entità senza sostituire l'entità esistente.
  • Sostituisci: Aggiornamenti un'entità esistente sostituendo l'intera entità.

L'esempio seguente mostra l'aggiornamento di un'entità mediante l'uso di upsertEntity:

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

Se l'entità da aggiornare non esiste, l'operazione di aggiornamento ha esito negativo; pertanto, se si vuole archiviare un'entità indipendentemente dal fatto che esista già, usare upsertEntity.

L'oggetto result per le operazioni di aggiornamento riuscite contiene l'Etag dell'entità aggiornata.

Usare i gruppi di entità

È talvolta consigliabile inviare più operazioni in un batch per garantire l'elaborazione atomica da parte del server. A tale scopo, creare una matrice di operazioni e passarla al submitTransaction metodo su TableClient.

Nell'esempio seguente viene dimostrato l'invio di due entità in un batch:

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

Per le operazioni in batch riuscite, result contiene le informazioni relative a ogni operazione nel batch.

Recuperare un'entità in base alla chiave

Per restituire un'entità specifica basata su PartitionKey e RowKey, usare il metodo getEntity.

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

Al termine di questa operazione, result contiene l'entità.

Eseguire query su un set di entità

Nell'esempio seguente viene compilata una query che restituisce i primi cinque elementi con partitionKey di 'hometasks' ed elencare tutte le entità nella tabella.

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

Eseguire query su un subset di proprietà di entità

Una query su una tabella può recuperare solo alcuni campi da un'entità. Questa tecnica permette di ridurre la larghezza di banda e di migliorare le prestazioni della query, in particolare per entità di grandi dimensioni. Usare la clausola select e passare i nomi dei campi da restituire. La query seguente, ad esempio, restituisce solo i campi 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;
}

Eliminazione di un'entità

È possibile eliminare un'entità utilizzando le relative chiavi di riga e di partizione. In questo esempio l'oggetto task1 contiene i valori rowKey e partitionKey dell'entità da eliminare. L'oggetto viene quindi passato al metodo deleteEntity .

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

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

Nota

Quando si eliminano elementi, è bene valutare l'uso di ETag per assicurarsi che l'elemento non sia stato modificato da un altro processo. Vedere Aggiornare un'entità per informazioni sull'uso di ETag.

Elimina una tabella

Nell'esempio di codice seguente viene illustrato come eliminare una tabella da un account di archiviazione.

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

Utilizzare i token di continuazione

Quando si esegue una query di tabelle di grandi quantità di risultati, ricercare i token di continuazione. Potrebbero essere disponibili grandi quantità di dati per la query di cui si potrebbe non essere consapevoli se non si compila il riconoscimento della presenza di un token di continuazione.

L'oggetto results restituito quando si esegue una query sulle entità imposta una proprietà continuationToken quando è presente un token di questo tipo. È possibile quindi utilizzarlo quando si esegue una query per continuare a spostarsi tra le entità della partizione e della tabella.

Quando si esegue una query, è possibile specificare un parametro continuationToken tra l'istanza dell'oggetto della query e la funzione di callback:

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

Usare le firme di accesso condiviso di Azure

Le firme di accesso condiviso rappresentano un modo sicuro per fornire accesso granulare alle tabelle senza specificare il nome o le chiavi dell'account di archiviazione. Le firme di accesso condiviso vengono spesso usate per fornire accesso limitato ai dati, ad esempio per consentire a un'app per dispositivi mobili di eseguire query sui record.

Un'applicazione attendibile, ad esempio un servizio basato sul cloud, genera una firma di accesso condiviso usando generateTableSas di TableClient e la fornisce a un'applicazione non attendibile o semi-trusted, ad esempio un'app per dispositivi mobili. La firma di accesso condiviso viene generata tramite un criterio che indica le date di inizio e di fine del periodo di validità della firma, nonché il livello di accesso concesso al titolare della firma di accesso condiviso.

L'esempio seguente genera un nuovo criterio di accesso condiviso che consentirà al titolare della firma di accesso condiviso di eseguire una query sulla tabella ('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
});

L'applicazione client usa quindi la firma di accesso condiviso con AzureSASCredential per eseguire operazioni sulla tabella. Nell'esempio seguente viene eseguita la connessione alla tabella e viene eseguita una query. Per il formato di tableSAS, vedere l'articolo Concedere accesso limitato alle risorse di Archiviazione di Azure usando firme di accesso condiviso (SAS).

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

Poiché la firma di accesso condiviso è stata generata con accesso solo query, se si prova a inserire, aggiornare o eliminare entità viene restituito un errore.

Elenchi di controllo di accesso

Per impostare i criteri di accesso per una firma di accesso condiviso è anche possibile usare un elenco di controllo di accesso. Questa soluzione è utile quando si vuole consentire a più client di accedere alla tabella, ma si impostano criteri di accesso diversi per ogni client.

Un elenco di controllo di accesso viene implementato usando una matrice di criteri di accesso, con un ID associato a ogni criterio. L'esempio seguente definisce due criteri, uno per 'user1' e uno per 'user2':

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

L'esempio seguente ottiene l'ACL corrente per la tabella hometasks e quindi aggiunge i nuovi criteri usando setAccessPolicy. Risultato:

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

Dopo avere impostato l'elenco di controllo di accesso, è possibile creare una firma di accesso condiviso in base all'ID di un criterio. Nell'esempio seguente viene creata una nuova firma di accesso condiviso per 'user2':

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

Passaggi successivi

Per altre informazioni, consultare le risorse seguenti.