Condividi tramite


Come usare Azure Table Storage o Azure Cosmos DB for Table da Node.js

SI APPLICA A: Tabella

Suggerimento

Il contenuto di questo articolo è applicabile alla risorsa di archiviazione di Azure Table e ad Azure Cosmos DB for Table. L'API per Table è un'offerta Premium per Azure Table Storage che include tabelle con ottimizzazione per la velocità effettiva, distribuzione globale e indici secondari automatici.

Questo articolo illustra come creare tabelle, archiviare i dati ed eseguire operazioni CRUD sui 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 ulteriori informazioni sulle differenze tra le offerte per tabelle in questi due servizi, vedere Panoramica dell'API per Table. 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 di Azure Cosmos DB for Table

Per istruzioni per la creazione di un account Azure Cosmos DB for Table, vedere Creare un account di database.

Configurare l'applicazione per l'accesso a Table Storage

Per usare Azure Storage o Azure Cosmos DB, è necessario disporre di Azure Storage SDK per Node.js, in cui è incluso un set di pratiche librerie che comunicano con i servizi di archiviazione REST.

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. Nella finestra di comando digitare il comando seguente:
   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 questa cartella si trova 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 Azure Storage o all'account Azure Cosmos DB for Table. Ottenere le credenziali in base al tipo di account in uso.

Creazione del client del servizio tabelle

Il codice seguente crea un TableServiceClient oggetto usando una credenziale di tipo TokenCredential. La DefaultAzureCredential classe crea una credenziale del token concatenato che funziona per la maggior parte delle applicazioni che usano Azure SDK provando più tipi di credenziali. Per ulteriori informazioni, vedere DefaultAzureCredential.

TokenCredential credential = new DefaultAzureCredential();

const tableService = new TableServiceClient(
  new Uri("<table-endpoint>"),
  credential
);

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 del servizio Table

Per interagire con una tabella, è necessario creare un oggetto TableClient usando le stesse credenziali usate per creare TableServiceClient. TableClient richiede 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 un valore partitionKey e uno rowKey, identificatori univoci dell'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 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 i metodi updateEntity e upsertEntity

  • Merge: aggiorna un'entità aggiornandone le proprietà senza sostituire l'entità esistente.
  • Replace: aggiorna un'entità esistente sostituendola interamente.

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. Di conseguenza, se si vuole archiviare un'entità indipendentemente dal fatto che sia già presente, 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 questo scopo, creare una matrice di operazioni e passarla al metodo submitTransaction in 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 in base a 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à

L'esempio seguente crea una query che restituisce i primi cinque elementi con PartitionKey 'hometasks' ed elenca tutte le entità presenti 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 tramite il metodo generateTableSas dell'oggetto TableClient e la fornisce a un'applicazione non attendibile o parzialmente attendibile, ad esempio a 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.

Nell'esempio seguente viene generato un nuovo criterio di accesso condiviso che consentirà al titolare della firma di accesso condiviso di eseguire una query ('r') per la tabella.

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 il metodo 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 recupera l'elenco di controllo di accesso corrente per la tabella hometasks e quindi aggiunge i nuovi criteri tramite 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.