Help us understand the problem. What is going on with this article?

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

環境

  • 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
  }
}

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした