Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?
@sayama0402

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

More than 1 year has passed since last update.

環境

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

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

1
Help us understand the problem. What is going on with this article?
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
sayama0402
Javascript(Riot.js / Vue / React / Nodejs) / PHP(Wordpress, cakePHP, Laravel) / Ruby(Ruby on Rails) / Python(Django) / SQL / Linux / Swift / Docker / AWS / Serverless

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
1
Help us understand the problem. What is going on with this article?