SOFTELメモ Developer's blog

会社概要 ブログ 調査依頼 採用情報 ...
てるてる動画

AWS SDK for PHP で DynamoDB する

問題

phpでDynamoDBしたいです。

答え

準備

テーブル作成: DynamoDBは、極論テーブルは1個に全部突っ込めみたいな世界なので tbl など適当な名前でもいいでしょう。単純なキーとデータの組み合わせならパーティションキーのみソートキーなしのテーブルもあり。

下のほうの例では、パーティションキー名をpkとしているが、そういうルールがあるわけではない。設計は自由。

接続ユーザー作成: IAMユーザーを作成。DynamoDBへの権限を付与。アクセスキー、シークレットアクセスキーを控えておく。

AWS SDK for PHP をインストール

https://docs.aws.amazon.com/ja_jp/sdk-for-php/v3/developer-guide/getting-started_installation.html#installing-via-composer

読み込む

DynamoDbClientを使って getItemやqueryするだけなら以下1行でよい。

use Aws\DynamoDb\DynamoDbClient;

必要に応じて以下など。

use Aws\DynamoDb\DynamoDbClient;
use Aws\DynamoDb\Marshaler;

接続情報の管理

接続情報は以下で設定できる。

設定方法は多数ある。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-files.html

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-precedence

php で環境変数を設定するなら putenv() でできる。

putenv('AWS_ACCESS_KEY_ID=AKIAI44QH8DHBEXAMPLE');
putenv('AWS_SECRET_ACCESS_KEY=je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY');

DynamoDBに接続する

接続情報が ~/.aws/credentials や環境変数の設定でよかったら、credentials など省略可能。

以下ではプログラム内で引数で渡している。

<?php
require 'aws-autoloader.php';

use Aws\DynamoDb\DynamoDbClient;

$client = new DynamoDbClient([
    'region' => 'ap-northeast-1',
    'version' => 'latest',
    'credentials' => [
        'key' => $access_key,
        'secret' => $secret_key,
    ],
    'http' => [
        'timeout' => 5,
    ],
]);

パラメータはこちらを参照

https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.AwsClient.html#___construct

‘version’ => ‘latest’ など省略でしてよさそうなものが必須項目だったりする。省略するとエラーになる。

上の例では timeout を指定したが、これは任意項目。省略可能。

DynamoDBに問い合わせる

getItem

プライマリキーなどで項目を取得

https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-dynamodb-2012-08-10.html#getitem

<?php
$result = $client->getItem([
    'Key' => [
        'pk' => [
            'S' => 'test'
        ]
    ],
    'TableName' => 'tbl'
]);

var_dump($result);

結果

object(Aws\Result)#132 (2) {
  ["data":"Aws\Result":private]=>
  array(2) {
    ["Item"]=>
    array(2) {
      ["pk"]=>
      array(1) {
        ["S"]=>
        string(4) "test"
      }
      ["xxxx"]=>
      array(1) {
        ["S"]=>
        string(32) "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
    ["@metadata"]=>
    array(4) {
      ["statusCode"]=>
      int(200)
      ["effectiveUri"]=>
      string(45) "https://dynamodb.ap-northeast-1.amazonaws.com"
      ["headers"]=> 

以下省略

結果は $result[‘Item’][‘xxxx’][‘S’] などで取得できる。

Aws\Result オブジェクトなので、 $result->get(‘Item’); でも取得できる。

query

インデックスを使って問い合わせ

https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-dynamodb-2012-08-10.html#query

<?php
$result = $client->query([
    'TableName' => 'tbl',
    'IndexName' => 'xxxx-index',
    'KeyConditionExpression' => 'xxxx = :xxxx',
    'ExpressionAttributeValues' => [
        ':xxxx' => [
            'S' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
        ],
    ],
    'Limit' => 10,
]);

結果

object(Aws\Result)#144 (2) {
  ["data":"Aws\Result":private]=>
  array(4) {
    ["Items"]=>
    array(1) {
      [0]=>
      array(2) {
        ["pk"]=>
        array(1) {
          ["S"]=>
          string(4) "test"
        }
        ["xxxx"]=>
        array(1) {
          ["S"]=>
          string(32) "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }
      }
    }
    ["Count"]=>
    int(1)
    ["ScannedCount"]=>
    int(1)
    ["@metadata"]=>

以下省略

結果は $result[‘Items’][0][‘xxxx’][‘S’] などで取得できる。

Aws\Result オブジェクトなので、 $result->get(‘Items’); でも取得できる。

結果が複数返ってくることもある。

scan

コストが高いので注意

https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-dynamodb-2012-08-10.html#scan

<?php
$result = $client->scan([
    'TableName' => 'tbl',
    'FilterExpression' => 'xxxx = :xxxx',
    'ExpressionAttributeValues' => [
        ':h' => [
            'S' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
        ],
    ],
    'Limit' => 10,
]);

結果はqueryと同様。

putItem

項目を作成

https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-dynamodb-2012-08-10.html#putitem

<?php
$client->putItem([
    'TableName' => 'tbl',
    'Item' => [
        'pk' => [
            'S' => 'abcdefg'
        ],
        '属性aaa' => [
            'S' => '属性値属性値属性値属性値'
        ],
    ],
]);

プライマリキーが重複していたら作成できない。

updateItem

項目を作成(存在しなければ作成、存在すれば更新)

https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-dynamodb-2012-08-10.html#updateitem

<?php
$client->updateItem([
    'TableName' => 'tbl',
    'AttributeUpdates' => [
        '属性名1234' => [
            'Value' => [
                'S' => '値値値値値値値値値値値値値値'
            ],
        ],
    ],
    'Key' => [
        'pk' => [
            'S' => 'パーティションキーなんとか'
        ],
    ]
]);

プライマリキーが重複していたら更新。項目が存在しなかったら作成。

deleteItem

項目を削除

https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-dynamodb-2012-08-10.html#updateitem

<?php
$client->deleteItem([
    'TableName' => 'tbl',
    'Key' => [
        'pk' => [
            'S' => $_REQUEST['s']
        ],
    ],
]);

DynamoDBのその他のメモ – 予約語

予約語が多数ある。

https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html

data, list, hash, user などの単語を属性名に使うと、データの保存はできるのに、queryするときに「予約語だよ」と言われてエラーになるなどやや面倒。

Invalid FilterExpression: Attribute name is a reserved keyword; reserved keyword: user

予約語のエラーを回避するには、ExpressionAttributeNames を使うなどが必要になる。

$db->scan([
    'TableName' => 'tbl',
    'ExpressionAttributeNames' => ['#U' => 'user'],
    'FilterExpression' => '#U = :u',
    'ExpressionAttributeValues' => [
        ':u' => ['S' => '太郎君'],
    ],
    'Limit' => 10,
]);

DynamoDBのその他のメモ – 問い合わせのSとかNとか

問い合わせの中にみられるSとかNとかの文字は何なのかというと、データ型記述子です。

https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Programming.LowLevelAPI.html

S – 文字列、N – 数値、BOOL – 真偽値 … などを表しています。

関連するメモ

コメント