Amazon DynamoDB2020年10月18日 | ||||||||||
はじめにkey-value 型データベース Amazon DynamoDB の使い方について。 テーブルの作成
検索は "スキャン" と "クエリー" で行う。スキャンは、全項目に対して属性についてのフィルターを適用するものである。クエリーは、プライマリキーの条件に合った項目を表示する。パーティションキーしかない場合のクエリーは特に面白くないので、クエリーは特にソートキーを持つ場合に意味があるのだろう。クエリーに対してフィルターを用いることもできる。 Lambda からのアクセス。 ロールに AmazonDynamoDBFullAccess をアタッチする。例: チャットルームの接続管理用テーブル例として、チャットルームの接続管理用のテーブルを考えてみる。名前は "ConnectionTable" とする。部屋 ID と接続 ID を結びつけたいので、プライマリキーのパーティションキーとして "roomId"、ソートキーとして "connectionId" を用意する。データは次のようになる。
AWS Lambda による DynamoDB テーブルへのアクセス方法AWS Lambda から DynamoDB テーブルにアクセスする方法として、AWS SDK の DynamoDB を用いる方法と、DynamoDB.DocumentClient を用いる方法がある。 DynamoDB const ddb = new AWS.DynamoDB({ apiVersion: "2012-10-08" }); DynamoDB.DocumentClient const docClient = new AWS.DynamoDB.DocumentClient(); 項目の追加DocumentClient 版const AWS = require("aws-sdk"); AWS.config.update({ region: process.env.AWS_REGION }); const docClient = new AWS.DynamoDB.DocumentClient(); exports.handler = (event) => { const params = { TableName: "ConnectionTable", Item: { roomId: "b", connectionId: "5" } }; docClient.put(params, function(err) { if (err) { console.error("Error", err); } else { console.log("Sucess"); } }); const response = { statusCode: 200, body: JSON.stringify(""), }; return response; }; params でテーブル名、項目を指定して、put() で追加している。 DynamoDB 版const AWS = require("aws-sdk"); AWS.config.update({ region: process.env.AWS_REGION }); const ddb = new AWS.DynamoDB({ apiVersion: "2012-10-08" }); exports.handler = (event) => { const params = { TableName: "ConnectionTable", Item: { roomId: { S: "c"}, connectionId: { S: "6"} } }; ddb.putItem(params, function (err) { if (err) { console.error("Error", err); } else { console.log("Success"); } }); const response = { statusCode: 200, body: JSON.stringify(""), }; return response; }; params でテーブル名、項目を指定して、putItem() で追加している。こちらの場合、属性の値を '{ S: "c" }' のように型と組み合わせて指定する必要がある。 項目の取得DocumentClient 版const params = { TableName: "ConnectionTable", Key: { roomId: "a", connectionId: "1" } }; docClient.get(params, function(err, data) { if (err) { console.error("Error", err); } else { console.log("Success", data); } }); 出力 { Item: { roomId: 'a', connectionId: '1' } } DynamoDB 版const params = { TableName: "ConnectionTable", Key: { roomId: { S: "b" }, connectionId: { S: "3" } } }; ddb.getItem(params, function(err, data) { if (err) { console.error("Error", err); } else { console.log("Success", data); } }); 出力 { Item: { roomId: { S: 'b' }, connectionId: { S: '3' } } } 項目の更新ここでは、部屋 ID と対応したメッセージを保存するテーブル MessageTable にメッセージを書き込むことを考える。 DocumentClient 版const params = { TableName: "MessageTable", Key: { roomId: "a" }, UpdateExpression: "set message = :m", ExpressionAttributeValues:{ ":m": "メッセージ" } }; docClient.update(params, function(err) { if (err) { console.error("Error", err); callback(new Error("Error")); } else { console.log("Sucess"); } }); DynamoDB 版const params = { TableName: "MessageTable", Key: { roomId: { S: "a" } }, UpdateExpression: "set message = :m", ExpressionAttributeValues:{ ":m": { S: "メッセージ" } } }; ddb.updateItem(params, function(err) { if (err) { console.error("Error", err); callback(new Error("Error")); } else { console.log("Sucess"); } }); 項目の削除DocumentClient 版const params = { TableName: "ConnectionTable", Key: { roomId: "b", connectionId: "5" } }; docClient.delete(params, function(err) { if (err) { console.error("Error", err); } else { console.log("Sucess"); } }); DynamoDB 版const params = { TableName: "ConnectionTable", Key: { roomId: { S: "c"}, connectionId: { S: "6"} } }; ddb.deleteItem(params, function (err) { if (err) { console.error("Error", err); } else { console.log("Success"); } }); クエリーパーティションキーで問い合わせする。属性に対してフィルター (FilterExpression) も使える。 DocumentClient 版const params = { TableName: "ConnectionTable", ProjectionExpression: "roomId, connectionId", KeyConditionExpression: "roomId = :rid", ExpressionAttributeValues: { ":rid": "a" } }; docClient.query(params, function(err, data) { if (err) { console.error("Error", err); } else { console.log("Success"); data.Items.map(({ roomId, connectionId }) => { console.log(roomId, connectionId); }); } }); 出力 a 1 a 2 DynamoDB 版const params = { TableName: "ConnectionTable", ProjectionExpression: "roomId, connectionId", KeyConditionExpression: "roomId = :rid", ExpressionAttributeValues: { ":rid": { S:"b" } } }; ddb.query(params, function(err, data) { if (err) { console.error("Error", err); } else { console.log("Success"); data.Items.map(({ roomId, connectionId }) => { console.log(roomId, connectionId); }); } }); 出力 { S: 'b' } { S: '3' } { S: 'b' } { S: '4' } ソートキーからパーティションキーを検索することはできない。そうしたい場合はスキャンを使う。 スキャン全項目をスキャンする。フィルター (FilterExpression) が使える。 DocumentClient 版const params = { TableName: "ConnectionTable", ProjectionExpression: "roomId, connectionId", FilterExpression: "roomId = :rid", ExpressionAttributeValues: { ":rid": "a" } }; docClient.scan(params, function(err, data) { if (err) { console.error("Error", err); } else { console.log("Success"); data.Items.map(({ roomId, connectionId }) => { console.log(roomId, connectionId); }); } }); 出力 a 1 a 2 params は、次のような書き方もできる。 const params = { TableName: "ConnectionTable", ProjectionExpression: "roomId, connectionId", FilterExpression: "#rid = :rid", ExpressionAttributeNames: { "#rid": "roomId" }, ExpressionAttributeValues: { ":rid": "a" } }; DynamoDB 版const params = { TableName: "ConnectionTable", ProjectionExpression: "roomId, connectionId", FilterExpression: "roomId = :rid", ExpressionAttributeValues: { ":rid": { S: "b" } } }; ddb.scan(params, function(err, data) { if (err) { console.error("Error", err); } else { console.log("Success"); data.Items.map(({ roomId, connectionId }) => { console.log(roomId, connectionId); }); } }); 出力 { S: 'b' } { S: '3' } { S: 'b' } { S: '4' } ある文字列で始まるパーティションキーを探すたとえば、部屋 ID が "xxx" で始まるものを探したいとすると、次のようにする。 const params = { TableName: "ConnectionTable", ProjectionExpression: "roomId, connectionId", FilterExpression: "begins_with(roomId, :rid)", ExpressionAttributeValues: { ":rid": "xxx" } }; docClient.scan(params, function(err, data) { if (err) { console.error("Error", err); } else { console.log("Success"); data.Items.map(({ roomId, connectionId }) => { console.log(roomId, connectionId); }); } }); 非同期処理非同期でクエリーを実行する場合は、非同期関数を用いる。 exports.handler = async (event) => { const params = { TableName: "ConnectionTable", ProjectionExpression: "roomId, connectionId", KeyConditionExpression: "roomId = :rid", ExpressionAttributeValues: { ":rid": "a" } }; try { const data = await docClient.query(params).promise(); console.log("Success"); data.Items.map(({ roomId, connectionId }) => { console.log(roomId, connectionId); }); } catch (e) { console.error("Error", e); } ... クエリーに対する処理が終わるのを待ちたい場合は、次のようにする。 let data; try { data = await docClient.query(params).promise(); console.log("Success"); } catch (e) { console.error("Error", e); callback(new Error("Error")); } let roomIds = {}; const postCalls = data.Items.map(async ({ roomId, connectionId }) => { console.log(roomId, connectionId); }); try { await Promise.all(postCalls); } catch (e) { console.log("Error", e); callback(new Error("Error")); } 参考 | ||||||||||
PENGUINITIS |