michimani.net

Python (boto3) で DynamoDB を操作する - put_item()/get_item()

2019-03-04

先日参加した AWS のハンズオンで DynamoDB を初めて触りました。そのときは Node.js で書かれたサンプルコードをコピペするだけで、データの読み/書きができました。 ということで、今回は Python でデータの読み/書きを実装してみたので、その時のメモです。

目次

テーブル作成

まずはテーブルを作成します。 今回は例として、欅坂46のメンバーブログの情報を保持するテーブルを作成してみます。あとでデータが取得しやすいように、 プライマリパーティションキープライマリソートキー は次のように設定します。

ブログの URL には自動採番された (であろう) 数値がパラメータとして付与されているので、 Url でソートすれば実質投稿順となります。

データの登録 put_item()

登録するデータは、次のような json を想定します。

{
  "Author": "欅坂46二期生",
  "Authorcode": "1001",
  "Entrydate": 20190224,
  "Images": [
    "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c.jpg",
    "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-01.jpg",
    "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-02.jpg",
    "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-03.jpg",
    "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-04.jpg",
    "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-05.jpg"
  ],
  "Title": "初歌番組。武元唯衣です。",
  "Url": "http://www.keyakizaka46.com/s/k46o/diary/detail/19596?ima=0000&cd=member"
}

boto3 を使って DynamoDB にデータを登録するには put_item() を使います。

import boto3

table_name = 'keyakizaka-blog'
item = {
  'Author': '欅坂46二期生',
  'Authorcode': '1001',
  'Entrydate': 20190224,
  'Images': [
    'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c.jpg',
    'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-01.jpg',
    'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-02.jpg',
    'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-03.jpg',
    'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-04.jpg',
    'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-05.jpg'
  ],
  'Title': '初歌番組。武元唯衣です。',
  'Url': 'http://www.keyakizaka46.com/s/k46o/diary/detail/19596?ima=0000&cd=member'
}

dynamo = boto3.client('dynamodb')
dynamo.put_item(TableName=table_name, Item=item)

とすると登録できます。…と思っていましたが、これでは出来ません。 リファレンスを読めば書いてるんですが、Item として指定する dict 型のオブジェクトの各項目に、それらの型が何なのかを、dict 型で指定する必要があります。例えば、上の例だと、 item として次のようなオブジェクトを定義する必要があります。

item = {
  'Author': {'S': '欅坂46二期生'},
  'Authorcode': {'S': '1001'},
  'Entrydate': {'N': '20190224'},
  'Images': {'L': [
    {'S': 'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c.jpg'},
    {'S': 'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-01.jpg'},
    {'S': 'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-02.jpg'},
    {'S': 'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-03.jpg'},
    {'S': 'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-04.jpg'},
    {'S': 'http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-05.jpg'}
  ]},
  'Title': {'S': '初歌番組。武元唯衣です。'},
  'Url': {'S': 'http://www.keyakizaka46.com/s/k46o/diary/detail/19596?ima=0000&cd=member'}
}

上に出てきているものでは

のような感じです。リスト内の項目についても、それぞれ型の指定が必要です。

また、N で数値を指定する際にも、数値ではなく文字列で値を定義する必要があります。上の例では Entrydate の部分で 'Entrydate': {'N': 20190224}, ではなく 'Entrydate': {'N': '20190224'} とします。

データの取得 get_item()

ここでいうデータの取得とは、単一のデータ取得です。 RDB の SELECT のような感じで複数データを取得する場合は query() を使いますが、それはまた次回。 単一のデータを取得する get_item() は、次のように使います。

import boto3

table_name = 'keyakizaka-blog'
dynamo = boto3.client('dynamodb')

res = dynamo.get_item(TableName=table_name, Key={
  'Authorcode': {'S': '1001'},
  'Url': {'S': 'http://www.keyakizaka46.com/s/k46o/diary/detail/19596?ima=0000&cd=member'}
})

データが存在していた場合は、下記のようなレスポンスが返ってきます。

{
    "Item": {
        "Title": {
            "S": "初歌番組。武元唯衣です。"
        },
        "Authorcode": {
            "S": "1001"
        },
        "Author": {
            "S": "欅坂46二期生"
        },
        "Images": {
            "L": [
                {
                    "S": "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c.jpg"
                },
                {
                    "S": "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-01.jpg"
                },
                {
                    "S": "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-02.jpg"
                },
                {
                    "S": "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-03.jpg"
                },
                {
                    "S": "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-04.jpg"
                },
                {
                    "S": "http://cdn.keyakizaka46.com/images/14/91e/fd0a1b0dec088e270f545ce11bd3c-05.jpg"
                }
            ]
        },
        "Entrydate": {
            "N": "20190224"
        },
        "Url": {
            "S": "http://www.keyakizaka46.com/s/k46o/diary/detail/19596?ima=0000&cd=member"
        }
    },
    "ResponseMetadata": {
        "RequestId": "CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXG",
        "HTTPStatusCode": 200,
        "HTTPHeaders": {
            "server": "Server",
            "date": "Mon, 03 Mar 2019 05:23:22 GMT",
            "content-type": "application/x-amz-json-1.0",
            "content-length": "776",
            "connection": "keep-alive",
            "x-amzn-requestid": "CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXG",
            "x-amz-crc32": "1759887117"
        },
        "RetryAttempts": 0
    }
}

データが存在しなかった場合は、下記のようなレスポンスになるので、Item キーの存在チェックでデータの存在チェックができます。

{
    "ResponseMetadata": {
        "RequestId": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXG",
        "HTTPStatusCode": 200,
        "HTTPHeaders": {
            "server": "Server",
            "date": "Mon, 03 Mar 2019 05:25:51 GMT",
            "content-type": "application/x-amz-json-1.0",
            "content-length": "2",
            "connection": "keep-alive",
            "x-amzn-requestid": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXG",
            "x-amz-crc32": "2745614147"
        },
        "RetryAttempts": 0
    }
}

まとめ

今回は boto3 の client.put_item() / client.get_item() を使いました。 ただ、どうやら以下のようにすることで Item に普通の dict を渡すことができるようです。

table_name = 'keyakizaka-blog'
dynamo = boto3.resource('dynamodb')
table = dynamo.Table('name')
table.put_item(Item={
  /* ... */
})

また、複数のデータを登録する際には、DynamoDB の BatchWriteItem オペレーションを利用するのが良さそうです。

あと、今回プライマリソートキーには文字列を指定していますが、ここに指定するのは数値のほうが良い気もしています。 そのあたりも含めて、もうちょっと DynamoDB 触ってみたいと思います。

このほかにも、 boto3 を使って DynamoDB を操作してみた話を書いているので、参考にしてみてください。


comments powered by Disqus