Node.js から Azure Table Storage または Azure Cosmos DB for Table を使用する方法

適用対象: Table

ヒント

この記事の内容は、Azure Table Storage と Azure Cosmos DB for Table に適用されます。 Table 用 API は、スループット最適化テーブル、グローバル分散、自動セカンダリ インデックスを提供するテーブル ストレージ用の Premium オファリングです。

この記事では、テーブルの作成、データの格納、データに対する CRUD 操作の実行を行う方法について説明します。 サンプルは Node.js で記述されています。

Azure サービス アカウントを作成する

Azure Table ストレージまたは Azure Cosmos DB を使用してテーブルを操作できます。 これら 2 つのサービスのテーブル サービスの違いについては、Table 用 API の概要に関するページを参照してください。 使用するサービスのアカウントを作成する必要があります。 以下のセクションでは、Azure Table ストレージと Azure Cosmos DB アカウントの両方を作成する方法について説明しますが、そのうちの 1 つのみを使用できます。

Azure Storage アカウントを作成する

Azure ストレージ アカウントを作成する最も簡単な方法は、Azure portal を利用することです。 詳細については、「 ストレージ アカウントの作成」を参照してください。

Azure PowerShell または Azure CLI を使って、Azure Storage アカウントを作成することもできます。

現時点でストレージ アカウントを作成しない場合は、Azure Storage エミュレーターを使って、ローカル環境でコードの実行とテストを行うこともできます。 詳細については、「開発とテストのための Azure のストレージ エミュレーター使用」を参照してください。

Azure Cosmos DB for Table アカウントを作成する

Azure Cosmos DB for Table アカウントの作成手順については、「データベース アカウントの作成」を参照してください。

テーブル ストレージにアクセスするようにアプリケーションを構成する

Azure Storage または Azure Cosmos DB を使用するには、Azure Tables SDK for Node.js が必要です。ここには、ストレージ REST サービスと通信するための便利なライブラリのセットが含まれています。

ノード パッケージ マネージャー (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 Table service に接続する

Azure Storage アカウントまたは Azure Cosmos DB for Table アカウントのいずれかに接続できます。 使用しているアカウントの種類に基づいて共有キーまたは接続文字列を取得します。

共有キーからの Table service クライアントの作成

Azure モジュールは、Azure Storage アカウントまたは Azure Cosmos DB に接続するために必要な情報として、環境変数の AZURE_ACCOUNT と AZURE_ACCESS_KEY と AZURE_TABLES_ENDPOINT を読み取ります。 これらの環境変数が設定されていない場合、TableServiceClient を呼び出すときにアカウント情報を指定する必要があります。 たとえば、次のコードでは、TableServiceClient オブジェクトを作成します。

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

const tableService = new TableServiceClient(
  endpoint,
  credential
);

接続文字列からの Table service クライアントの作成

Azure Cosmos DB または Storage の接続を追加するには、TableServiceClient オブジェクトを作成し、アカウント名、主キー、およびエンドポイントを指定します。 これらの値は、自分の Azure Cosmos DB アカウントまたは Storage アカウントの Azure portal で [設定]>[接続文字列] を選択することによりコピーできます。 次に例を示します。

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

テーブルを作成する

createTable の呼び出しにより、指定した名前の新しいテーブルが (まだ存在していない場合は) 作成されます。 次の例では、"mytable" という名前のテーブルが存在しない場合、このテーブルを作成します。

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

テーブル クライアントの作成

テーブルを操作するには、TableServiceClient の作成に使用したのと同じ資格情報を使用して TableClient オブジェクトを作成する必要があります。 TableClient には、ターゲット テーブルの名前も必要です。

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

エンティティをテーブルに追加する

エンティティを追加するには、エンティティのプロパティを定義するオブジェクトを最初に作成します。 すべてのエンティティには、エンティティの一意の識別子である PartitionKeyRowKey が含まれます。

  • partitionKey - エンティティが格納されるパーティションを決定します。
  • rowKey - パーティション内のエンティティを一意に識別します。

partitionKeyrowKey は両方とも文字列値にする必要があります。

エンティティを定義する例を次に示します。 dueDate は、Date の型として定義されています。 型の指定は省略可能です。型を指定しなかった場合、型は推測されます。

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

Note

各レコードには、エンティティが挿入または更新される場合に Azure により設定される Timestamp フィールドもあります。

テーブルにエンティティを追加するには、エンティティ オブジェクトを 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 が含まれます。

エンティティのグループを操作する

状況によって、複数の操作をバッチとして送信し、サーバーによるアトミック処理を行うことが合理的である場合があります。 これを実現するには、操作の配列を作成し、TableClientsubmitTransactionメソッドに渡します。

次の例に、2 つのエンティティをバッチで送信する方法を示します。

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 にはバッチ内の各操作の情報が含まれます。

キーを使用したエンティティを取得する

PartitionKeyRowKey に基づいて特定のエンティティを返すには、getEntity メソッドを使います。

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

この操作を完了すると、result にはエンティティが含まれます。

エンティティのセットを照会する

次の例では、"hometasks" の PartitionKey で最初の 5 つの項目を返し、テーブル内のすべてのエンティティを一覧表示するクエリを作成します。

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 オブジェクトに、削除するエンティティの rowKeypartitionKey の値が格納されます。 次に、このオブジェクトが 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);
   }
 }

共有アクセス署名を操作する

共有アクセス署名 (SAS) は、ストレージ アカウントの名前またはキーを指定せずにテーブルへの細密なアクセスを提供する安全な方法です。 多くの場合、SAS は、モバイル アプリでのレコードの照会などデータへの限定的なアクセスのために使用されます。

クラウドベースのサービスなどの信頼されたアプリケーションは、TableClientgenerateTableSas を使って SAS を生成し、信頼されていないか、モバイル アプリなどの部分的に信頼されたアプリケーションにこれを提供します。 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 を使用してテーブルに対する操作を実行します。 次の例では、テーブルに接続してクエリを実行しています。 tableSAS の形式については、「共有アクセス署名 (SAS ) を使用して Azure Storage リソースへの制限付きアクセスを許可する」の記事を参照してください。

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

SAS がクエリ アクセスのみで生成されたので、エンティティの挿入、更新、または削除を試行するとエラーが返されます。

アクセス制御リスト

SAS のアクセス ポリシーを設定するために、アクセス制御リスト (ACL) も使用できます。 複数のクライアントにテーブルへのアクセスを許可し、各クライアントに異なるアクセス ポリシーを提供する場合に便利です。

ACL は、アクセス ポリシーの配列と、各ポリシーに関連付けられた ID を使用して実装されます。 次の例では、2 つのポリシーを定義しています。1 つは "user1" 用、もう 1 つは "user2" 用です。

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

次の例では、現在の hometasks テーブルの ACL を取得し、setAccessPolicy を使って新しいポリシーを追加しています。 この手法で以下を実行できます。

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

ACL を設定した後で、ポリシーの ID に基づいて SAS を作成できます。 次の例では、"user2" 用に新しい SAS を作成しています。

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

次のステップ

詳細については、次のリソースを参照してください。