AWS SDK for Rust の Developer Preview が発表されました。
examplesにDynamoDB操作関連のソースコードが載っているので
いくつか触ってみたいと思います。
今回は Query による検索を試します。
AWS SDK for Rust を使ってみる
- query のサンプルを実行
- query + GSI のサンプルを実行
- query による検索結果のレスポンスを解析
Queryで絞り込み条件を指定してデータを取得する
検証環境
- macOS:Big Sur 11.6
- Rust:1.57.0
- AWS SDK for Rust:v0.2.0
環境変数の設定
認証情報の取得は環境変数からおこなうため、以下の環境変数を設定します。
- AWS_DEFAULT_REGION
- AWS_SECRET_ACCESS_KEY
- AWS_ACCESS_KEY_ID
詳しくは、READMEで確認してください。
テーブルの作成
DynamoDBに Users テーブルを作成し、スラムダンク 湘北高校のメンバーを登録します。
- テーブル名:Users
- パーティションキー:Id(Number)
- ソートキー:なし
{
"users": [
{
"Id": 1,
"Name": "桜木花道",
"Grade": 1,
"Position": "PF",
"Number": 10,
"Height": 189,
"Weight": 83
},
{
"Id": 2,
"Name": "流川楓",
"Grade": 1,
"Position": "SF",
"Number": 11,
"Height": 187,
"Weight": 75
},
{
"Id": 3,
"Name": "赤木剛憲",
"Grade": 3,
"Position": "C",
"Number": 4,
"Height": 197,
"Weight": 93
},
{
"Id": 4,
"Name": "宮城リョータ",
"Grade": 2,
"Position": "PG",
"Number": 7,
"Height": 168,
"Weight": 59
},
{
"Id": 5,
"Name": "三井寿",
"Grade": 3,
"Position": "SG",
"Number": 14,
"Height": 184,
"Weight": 70
},
{
"Id": 6,
"Name": "木暮公延",
"Grade": 3,
"Position": "SF",
"Number": 5,
"Height": 178,
"Weight": 62
}
]
}
Queryでデータを取得する
Cargo.toml
依存クレートを設定します。
[dependencies]
aws-config = "0.2.0"
aws-sdk-dynamodb = "0.2.0"
tokio = { version = "1", features = ["full"] }
main.rs
use aws_sdk_dynamodb::{Client};
use aws_sdk_dynamodb::model::{AttributeValue};
#[tokio::main]
async fn main() {
let config = aws_config::load_from_env().await;
let client = Client::new(&config);
let resp = client
.query()
.table_name("Users")
.key_condition_expression("#key = :value".to_string())
.expression_attribute_names("#key".to_string(), "Id".to_string())
.expression_attribute_values(":value".to_string(), AttributeValue::N("1".to_string()))
.send()
.await;
match resp {
Ok(query_output) => {
if let Some(items) = query_output.items {
for item in items {
println!("{:?}", item);
// Idを取り出す
if let Some(attr_val) = item.get("Id") {
if let Ok(id_val) = attr_val.as_n() {
if let Ok(id) = id_val.parse::<u32>() {
println!("{}", id);
}
}
}
// Nameを取り出す
if let Some(attr_val) = item.get("Name") {
if let Ok(name) = attr_val.as_s() {
println!("{}", name.to_string());
}
}
}
}
}
Err(e) => {
println!("{}", e);
}
}
}
環境変数に設定した認証情報を取得するため、configを生成します。
その後、DynamoDBのクライアントを生成します。
.table_name()
でテーブル名を指定し、.send()
でリクエストを送信します。
以下を使用することで、Queryで絞り込むための条件を構成します。
- .key_condition_expression()
- .expression_attribute_names()
- .expression_attribute_values()
上記ソースコードでは、Id = {N: 1}で検索しています。
非同期メソッドで実装されているため、.await
が必要です。
Idの取得では.as_n()
、Nameの取得では.as_s()
を使用しています。
取得結果のId は&String
であるため、
数値として扱う場合は.parse()
等で変換する必要があるので注意です。
以下、実行結果です。
{"Grade": N("1"), "Id": N("1"), "Weight": N("83"), "Height": N("189"), "Name": S("桜木花道"), "Number": N("10"), "Position": S("PF")}
1
桜木花道
GSIを使用したQuery
GSIを作成する
グローバルセカンダリインデックスを作成します。
- パーティションキー:Position(String)
- ソートキー:Id(Number)
- インデックス名:Position_Id_Index
main.rs
use aws_sdk_dynamodb::{Client};
use aws_sdk_dynamodb::model::{AttributeValue};
#[tokio::main]
async fn main() {
let config = aws_config::load_from_env().await;
let client = Client::new(&config);
let resp = client
.query()
.table_name("Users")
.index_name("Position_Id_Index")
.key_condition_expression("#key = :value".to_string())
.expression_attribute_names("#key".to_string(), "Position".to_string())
.expression_attribute_values(":value".to_string(), AttributeValue::S("SF".to_string()))
.send()
.await;
match resp {
Ok(query_output) => {
if let Some(items) = query_output.items {
for item in items {
println!("{:?}", item);
// Idを取り出す
if let Some(attr_val) = item.get("Id") {
if let Ok(id_val) = attr_val.as_n() {
if let Ok(id) = id_val.parse::<u32>() {
println!("{}", id);
}
}
}
// Nameを取り出す
if let Some(attr_val) = item.get("Name") {
if let Ok(name) = attr_val.as_s() {
println!("{}", name.to_string());
}
}
}
}
}
Err(e) => {
println!("{}", e);
}
}
}
テーブルに対してQueryを実行する場合との違いを説明します。
まず、.index_name()
でインデックス名を指定します。
そして、.expression_attribute_names()
でGSIのプライマリーキーであるPositionを指定するように修正します。
Positionは文字列(String)であるため、.expression_attribute_values()
ではAttributeValue::S()
を使用します。
以下、実行結果です。
{"Id": N("2"), "Number": N("11"), "Position": S("SF"), "Grade": N("1"), "Weight": N("75"), "Name": S("流川楓"), "Height": N("187")}
流川楓
11
{"Position": S("SF"), "Number": N("5"), "Weight": N("62"), "Grade": N("3"), "Name": S("木暮公延"), "Id": N("6"), "Height": N("178")}
木暮公延
5
フィルターでデータを絞り込む
フィルターを使い、プライマリーキーやソートキー以外の絞り込み条件を追加することも可能です。
let resp = client
.query()
.table_name("Users")
.index_name("Position_Id_Index")
.key_condition_expression("#key = :value".to_string())
.expression_attribute_names("#key".to_string(), "Position".to_string())
.expression_attribute_values(":value".to_string(), AttributeValue::S("SF".to_string()))
.filter_expression("#filterKey >= :filterValue".to_string())
.expression_attribute_names("#filterKey".to_string(), "height".to_string())
.expression_attribute_values(":filterValue".to_string(), AttributeValue::N("180".to_string()))
.send()
.await;
まとめ
Scan同様に、Queryも書くことができました。ありがとう、SDK。
コメント