LoginSignup
6
5

More than 3 years have passed since last update.

Node.jsでGlobal Secondary Indexを使用して特定条件のレコードを抽出する

Posted at

環境

  • Nodejs
  • AWS Lambda
  • AWS DynamoDB

はじめに

DynamoDBではパーティションキーもしくはレンジキーを使用してしか基本的には抽出が出来ないのですが、任意のキーを元に抽出を行いたいという時は、Global Secondary Index(以下GSI)を使用する事で任意のキーでレコードを抽出することが出来ます。

注意点

以下の点に気をつける必要があります。
* GSIは1テーブルにつき20件までしか作成出来ない
* GSIのキーに指定出来るカラムのデータ型は文字列、数値、バイナリのいずれかである必要があります
* Serverless Frameworkではまだそこまで自由なGSIは作成出来ないようなので、DynamoDBコンソールからGSIを作成する必要がある(ハッシュキー or レンジキー以外でのGSIの作成がうまくいかなかった)

例えばboolean型のカラムをキーにGSIは作成出来ません(私がやろうとしていました...)

参考情報:
* DynamoDB での制限

前提

適当ですが、以下のようなUsersテーブルがあるとします。

カラム名 データ型 キー
username string hash
age integer range
isPremier integer

isPremierカラムは01が整数で入るとします。
そしてisPremier0のレコードを全件取得したいというのが実現したいことです。

動作サンプルの手順

  1. AWS DynamoDB ConsoleからGSIを作成
  2. queryを行うLambdaを作成

AWS DynamoDB ConsoleからGSIを作成

AWSのDynamoDB Consoleページ > テーブル > インデックス にアクセスします

そしてインデックスの作成ボタンから新規のGSIを以下のように作成します。

スクリーンショット 2019-11-26 23.30.36.png

queryを行うLambdaを作成

NodejsでLambda関数を作成します。
先ほど作成したGSIの以下の情報を使用します。
* テーブル名:Users
* インデックス名:isPremier-index
抽出条件はisPremierが0のレコードを全件取得

const AWS = require('aws-sdk')
const DynamoDB = new AWS.DynamoDB.DocumentClient({region: "ap-northeast-1"})

module.exports.hello = async (event, context) => {
  try {
    const params = {
      TableName: 'Users', // テーブル名
      IndexName: 'isPremier-index', // 作成したGSI名
      KeyConditionExpression: '#indexKey = :indexValue', // 条件を指定
      ExpressionAttributeNames : {
        "#indexKey"  : 'isPremier' // GSIの作成時に指定したキー名を設定
      },
      ExpressionAttributeValues: {
        ':indexValue': 0 // isPremierの0を抽出
      }
    }
    let items = [] // 抽出したレコードを格納するための空の配列を定義

    const query = async () => {
      console.log('start query')
      let result = await DynamoDB.query(params).promise()
      items.push(...result.Items)

      // LastEvaluatedKeyが存在していたら再帰的にqueryを実行
      if(result.LastEvaluatedKey){
        params.ExclusiveStartKey = result.LastEvaluatedKey
        await query()
      }
    }
    await query()
    console.log(`Execution result: ${items.length}`)
  } catch (err) {
    console.error(`[Error]: ${JSON.stringify(err)}`)
    return err
  }
}

以上で条件にあったレコードを全件取得出来ます。

6
5
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
6
5