DynamoDBの query() で FilterExpression を使ってデータ取得条件を設定する

DynamoDBテーブルから情報取得する際に用いるquery()メソッドでFilterExpressionを使ってみた例です。
2021.01.08

何らかの情報取得APIを作るとき、権限チェックをします。たとえば、「Aさんが所持しているデバイスか?」といった具合です。他人のデバイスの情報取得をしている場合、それは403エラー等で失敗させる必要があります。

情報取得APIの例

このような実装を考えてみました。

おすすめの方

  • DynamoDBのget_item()を参考にしたい方
  • DynamoDBのquery()を参考にしたい方

実験用のDynamoDBテーブルを用意する

適当なDynamoDBテーブルを作成します。

DynamoDBテーブルを作成

サンプルデータを用意します。

適当なサンプルデータを追加

{
  "userId": "test1",
  "devices": [
    "d0001",
    "d0002"
  ]
}

例1: ソースコードで判定する

DynamoDBテーブルから「指定したユーザが所持するデバイス一覧」を取得し、判定する例です。 指定デバイスを所持しているか?の判定をif文で行っています。

lambda.py

import boto3
from boto3.dynamodb.conditions import Key, Attr

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('user-table')

options = {
    'Key': {
        'userId': 'test1',
    },
    'ProjectionExpression': '#devices',
    'ExpressionAttributeNames': {
        '#devices': 'devices'
    }
}
res = table.get_item(**options)

if 'd0001' in res['Item']['devices']:
    print('ok')
else:
    print('ng')

例2: FilterExpression を活用する

DynamoDBテーブルから「指定したユーザが指定したデバイスを所持する件数」を取得し、判定する例です。 指定デバイスを所持しているか?の判定はDynamoDB側に任せています。

lambda.py

import boto3
from boto3.dynamodb.conditions import Key, Attr

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('user-table')

options = {
    'Select': 'COUNT',
    'KeyConditionExpression': Key('userId').eq('test1'),
    'FilterExpression': Attr('devices').contains('d0001'),
}
res = table.query(**options)

if res['Count'] != 0:
    print('ok')
else:
    print('ng')

おまけ

DynamoDBで使える条件式は下記が参考になります。

よく使うのは下記だと思います(個人の感想)。

  • between
  • eq
  • ne
  • contains

また、FilterExpressionは、&|で複合条件ができます。

options = {
    'KeyConditionExpression': Key('userId').eq('test1'),
    'FilterExpression': Attr('devices').contains('d0001') & Attr('aaa').eq('bbb') | Attr('xxx').ne('yyy'),
}
res = table.query(**options)

さいごに

本記事ではかなりシンプルな例でしたが、FilterExpressionでは様々な条件の組み合わせも可能です。ぜひ活用してみてください。

参考