0
0

DynamoDB&Golang Queryまとめ

Posted at

Queryで使用するdynamodb/api.goに書かれたQueryInputは以下の通りです。

以下に、スペースを全て詰めた表を提供します。

フィールド名 タイプ 説明 デフォルト値 SQLでの類似概念
*ConsistentRead *bool 読み取りの整合性モデルを決定。trueの場合、強い整合性の読み取りを使用。グローバルセカンダリインデックスではサポートされていない。 false SELECT with FOR UPDATE
ExclusiveStartKey map[string]*AttributeValue 評価を開始する最初のアイテムのプライマリキー。 nil OFFSET
*ExpressionAttributeNames map[string]*string 式内の属性名の代用トークン。 nil AS (エイリアス)
*ExpressionAttributeValues map[string]*AttributeValue 式内の属性値の代用トークン。 nil プレースホルダー (?)
*FilterExpression *string Query操作後に適用される条件。 nil WHERE (追加フィルター)
IndexName *string クエリを実行するインデックスの名前。 nil INDEX (インデックス指定)
*KeyConditionExpression *string アイテムを取得するためのキー条件を指定する式。 nil WHERE (主キー条件)
*Limit *int64 評価する最大アイテム数。 nil LIMIT
*ProjectionExpression *string 取得する属性を指定する式。 nil SELECT
ReturnConsumedCapacity *string レスポンスに含まれるスループット消費情報のレベルを決定。 NONE なし
ScanIndexForward *bool インデックスの走査順序を決定。trueの場合、昇順。 true ORDER BY
*Select *string 結果に含まれる属性を決定。 ALL_ATTRIBUTES SELECT
*TableName *string アイテムを含むテーブルの名前。必須フィールド。 nil FROM

定義にAttributesToGet・ConditionalOperator・QueryFilter・KeyConditionsが含まれていたが、これらはレガシーパラメータのため使用されない模様。

表記方法

TableName

これはそのままの意味でテーブルの名前を指定します。

input := &dynamodb.QueryInput{
    TableName: aws.String("TableName"),
}

KeyConditionExpression&ExpressionAttributeValues

アイテムを取得するためのキー条件を指定する式で、SQLのWHERE句みたいなものです。
ExpressionAttributevaluesで具体的な値を指定します。

KeyCondtionExpressionValuesで使用できる条件は以下の通りです。

条件 説明
a = b true if the attribute a is equal to the value b
a < b true if a is less than b
a <= b true if a is less than or equal to b
a > b true if a is greater than b
a >= b true if a is greater than or equal to b
a BETWEEN b AND c true if a is greater than or equal to b, and less than or equal to c
begins_with (a, substr) true if the value of attribute a begins with a particular substring

これらの条件をKeyConditionExpressionで指定し:hogeで書かれた値をExpressionAttributeValuesでセットします。

例えば以下のようなデータがあるとします。

PrimaryKey (OrderID) SortKey (OrderDate) CustomerName Amount
1001 2023-01-01 Alice 50
1001 2023-01-02 Bob 30
1002 2023-01-01 Carol 70
1002 2023-01-03 Dave 40
1003 2023-01-02 Eve 20

このデータに対して以下のQueryを投げると、

input := &dynamodb.QueryInput{
    TableName: aws.String("Orders"),
    KeyConditionExpression: aws.String("OrderID = :pk AND OrderDate BETWEEN :start AND :end"),
    ExpressionAttributeValues: map[string]types.AttributeValue{
        ":pk": &types.AttributeValueMemberS{Value: aws.String("1002")},
        ":start": &types.AttributeValueMemberS{Value: aws.String("2023-01-01")},
        ":end": &types.AttributeValueMemberS{Value: aws.String("2023-01-03")},
    },
}

以下のようなデータを取得することができます。
これはOrdersテーブルからPKが1002で、2023-01-01から2023-01-03のデータを取得するという意味だからです。

OrderID OrderDate CustomerName Amount
1002 2023-01-01 Carol 70
1002 2023-01-03 Dave 40

Limit

評価する最大アイテム数。

input := &dynamodb.QueryInput{
    TableName: aws.String("YourTableName"),
    Limit: aws.Int64(10),
}

指定した件数取得する設定です。
ただ、この設定はDynamoDBでは思った挙動にならないこともあるようで、使い方が意外と難しい模様です。

input := &dynamodb.QueryInput{
    TableName: aws.String("TableName"),
    Limit: aws.Int64(10),
}

例えば、以下の記事にあるように後述するFilterExpressionを使用すると、これはQuery操作後に適用される条件のため10件取得と設定しても、10件取得したデータに対してFilterをかけてしまい思った挙動にならないようです。
https://www.denzow.me/entry/2018/02/04/130419

FilterExpression

Limitの説明でも出てきましたが、Query操作後に適用される条件です。
ExpressionAttributevaluesで具体的な値を指定します。
上述した通り、データ取得後にFilterExpressionが実行されるため、その点には注意が必要です。

    input := &dynamodb.ScanInput{
        TableName: aws.String("Orders"),
        FilterExpression: aws.String("Amount <= :amount"),
        ExpressionAttributeValues: map[string]types.AttributeValue{
            ":amount": &types.AttributeValueMemberN{Value: "40"},
        },
    }

ProjectionExpression

取得したい特定の属性を指定するために使用します。
例えば、以下のようなテーブルがあるとしましょう。

PrimaryKey (OrderID) SortKey (OrderDate) CustomerName Amount
1001 2023-01-01 Alice 50
1001 2023-01-02 Bob 30
1002 2023-01-01 Carol 70
1002 2023-01-03 Dave 40
1003 2023-01-02 Eve 20

ここで以下のqueryで設定すると、

input := &dynamodb.ScanInput{
    TableName: aws.String("Orders"),
    ProjectionExpression: aws.String("OrderID, Amount"),
}

以下のように指定した属性のみ取得することが可能となります。

OrderID Amount
1001 50
1001 30
1002 70
1002 40
1003 20

SELECT

これは取得する属性を指定するという点でProjectionExpressionと非常に似ています。
そのため、SELECTProjectionExpressionを同時に使用することはできません。ただし、SelectがSPECIFIC_ATTRIBUTESの場合は例外です。(ただ、一緒に使う意味がないので実際に同時に使うことはなさそう。)

というよりおそらくProjectionExpressionSELECTのオプションの1つのよう(間違ってるかも。)

表でまとめると以下の通りとなります。
ただ、デフォルトで全ての属性を取得するのでALL_ATTRIBUTESは使わないだろうし、SPECIFIC_ATTRIBUTESProjection Expressionだけ指定すればいいから特に指定する必要はなさそうだし、あまり使う機会がなさそう。

唯一使えそうなのはCOUNTくらいかな?

オプション 説明 利用ケース
ALL_ATTRIBUTES 指定されたテーブルまたはインデックスの全てのアイテム属性を返す。 全ての属性を取得したい場合に使用。
ALL_PROJECTED_ATTRIBUTES インデックスをクエリする場合にのみ使用可能。インデックスにプロジェクトされた全ての属性を取得。 インデックスが全ての属性をプロジェクトするように設定されている場合に使用。
COUNT 一致するアイテムの数を返す。実際のアイテムそのものではない。 クエリの結果のアイテム数を知りたい場合に使用。
SPECIFIC_ATTRIBUTES 特定の属性のみを返す。ProjectionExpressionと組み合わせて使用。 特定の属性のみを取得したい場合に使用。
ProjectionExpression 特定の属性を指定して取得する。 特定の属性のみを取得したい場合に使用。
例えば、以下のように設定すれば検索結果のデータではなく、検索件数を取得できる。
input := &dynamodb.QueryInput{
    TableName: aws.String("Orders"),
    KeyConditionExpression: aws.String("OrderID = :id"),
    ExpressionAttributeValues: map[string]types.AttributeValue{
        ":id": &types.AttributeValueMemberS{Value: aws.String("1001")},
    },
    Select: types.SelectCount,
}

んー、でも結局これもQueryOutputのScannedCountCountフィールドがあるからそれを使えばいいから結局SELECTの使い道っていまいち分からない。。。😅

以下はQueryOutputのメモです。

フィールド名 説明
Items クエリによって返されるアイテムのリスト。
Count クエリによって返されたアイテムの数。
ScannedCount フィルタリング前にスキャンされたアイテムの数。
LastEvaluatedKey ページングが必要な場合に、次のページの開始キーを示す。

ExpressionAttributeNames

ExpressionAttributeNamesは、予約語や特殊文字を含む属性名のエイリアスを指定するために使用されます。SQLだとASと同じようなものです。同じようなものです。

例えば以下のテーブル属性のCustomerNameが予約語だったとしましょう。

PrimaryKey (OrderID) SortKey (OrderDate) CustomerName Amount
1001 2023-01-01 Alice 50
1001 2023-01-02 Bob 30
1002 2023-01-01 Carol 70
1002 2023-01-03 Dave 40
1003 2023-01-02 Eve 20

その場合、以下のように#hogeと書くことでCustomerNameを使用することができます。

input := &dynamodb.ScanInput{
    TableName: aws.String("Orders"),
    ProjectionExpression: aws.String("OrderID, #n, Amount"),
    ExpressionAttributeNames: map[string]string{
        "#n": "CustomerName",
    },
}

ConsistentRead

読み取りの整合性モデルを決定します。trueの場合、強い整合性の読み取りを使用。グローバルセカンダリインデックスではサポートされていません。

input := &dynamodb.QueryInput{
    TableName:      aws.String("YourTableName"),
    ConsistentRead: aws.Bool(true),
}

まとめ

Queryで使用するオプションを今回は調べてまとめてみました。
頭が整理できてよかったです🙌

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0