web-dev-qa-db-ja.com

非主キーフィールドを使用してDynamoDBにクエリを実行するにはどうすればよいですか?

DynamoDBテーブルに次のデータがあります。

enter image description here

これが私のコードです:

const userStatusParams = {
        TableName: process.env.USERSTATUS_TABLE,
        KeyConditionExpression: "loggedIn = :loggedIn",
        ExpressionAttributeValues: {
          ":loggedIn": true
        }
      };
      var usersResult;
      try {
        usersResult = await dynamoDbLib.call("query", userStatusParams);
        console.log(usersResult);
      }catch (e) {
        console.log("Error occurred querying for users belong to group.");
        console.log(e);
      }

Amazonはこのエラーを返します:

{ ValidationException: Query condition missed key schema element: userId
    at Request.extractError ...

loggedIn == trueであるすべてのレコードを返すにはどうすればよいですか?

私のデータベースは現在、serverless.yml構成を介してこのように構成されています。

phoneNumberTable: #This table is used to track phone numbers used in the system.
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:custom.phoneNumberTable}
        AttributeDefinitions: #UserID in this case will be created once and constantly updated as it changes with status regarding the user.
          - AttributeName: phoneNumber
            AttributeType: S
        KeySchema:
          - AttributeName: phoneNumber
            KeyType: HASH
        ProvisionedThroughput:
            ReadCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.pstage}}
            WriteCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.pstage}}

私は他の答えを介してこれについて少し調査しましたが、私の状況を理解することができませんでした。他の回答では、ソートキーがありましたが、ここではソートキーを使用しません。

7
Joseph Astrahan

queryを実行している場合は、主キー(この場合はuserId)を渡す必要があります。 primaryKeyがなく、すべてのlogged in = trueフィールドが必要な場合は、次のようにscanを使用してfilterExpressionを実行できます。

const userStatusParams = {
        TableName: process.env.USERSTATUS_TABLE,
        FilterExpression: 'loggedIn = :loggedIn',
        ExpressionAttributeValues: {
          ":loggedIn": true
        }
      };
      var usersResult;
      try {
        // Do scan
        usersResult = await dynamoDbLib.call("scan", userStatusParams);
        console.log(usersResult);
      }catch (e) {
        console.log("Error occurred querying for users belong to group.");
        console.log(e);
      }

更新:scan操作の効率が低いため、この問題を解決するもう1つの方法は、GSIを作成することです。 、主キーloggedInを使用します。ただし、ここでの問題は、 booleanデータ型。 を持つフィールドの主キーを作成できないことです。 number, string, binaryである必要があります。したがって、gsiを作成するには、受け入れられたデータ型をloggedInではなくbooleanフィールドに格納する必要があります。

1000レコードのテーブルに対してパフォーマンスにどの程度の影響があるかはわかりませんが、gsiの良いところは、それらを作成できることです 後で既存のテーブルでも 将来的には、パフォーマンスへの影響がわかります。また、テーブルに作成できるgsiの数は5に制限されています。したがって、gsiを賢く利用してください。

7
Prakash Sharma

スキャン操作は常にテーブル全体またはセカンダリインデックスをスキャンし、値をフィルターで除外して目的の結果を提供します。基本的に、結果セットからデータを削除するという追加の手順が追加されます。可能であれば、多くの結果を削除するフィルターを使用して、大きなテーブルまたはインデックスでスキャン操作を使用することは避けてください。 続きを読む

グローバルセカンダリインデックスを使用する必要があります!

AWSコンソール> DynamoDb>タブテーブルのインデックス>インデックスの作成>

primary key - loggedIn
secondary key - userId
projected attributes - all

一意のペアを持つために、2次キーを追加する必要があります。 loginは一意である必要があるため、インデックス名(loggedIn)は使用しないでください。

主キー(loggedIn)でQueryメソッドを使用できるより

2
Dmitry Grinko

dynamodbテーブルをクエリするには、インデックス付きフィールドでのみクエリを実行できます。インデックス付きフィールドには次のものがあります。

  1. 主キー
  2. セカンダリグローバルインデックスハッシュ

loggedInレコードを照会するには、loggedInフィールドにグローバルセカンダリインデックスを追加する必要があります。

すべてのloggedInレコードには2つの値(true/false)があり、大容量でない限り、これにより多くのスループットエラーが発生するため、データの場合はこれを行いません。 (パーティション間でのハッシュ分散が悪いために作成された「ホット」キーは常に存在します)

それでもdynamodbでこのクエリを使用する場合は、「ホット」キーを防ぐために「loggedIn」値を変更する必要があります

解決策は、データにサフィックスを追加することです:(true.0、true.1 ... true.N)

Nは[このインデックスに予想されるパーティション+ある程度の成長ギャップ](高負荷または多くの「true/false」が予想される場合は、N = 200を選択できます)(パーティション間での適切なハッシュ分散のため)である必要があります。 NはuserIdを法とすることをお勧めします。 (これは、userIdによる操作を行うのに役立ちます。)

1
Eyal Ch