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 | ||||||||||