Search code examples
phpdatabase-designamazon-web-servicesnosqlamazon-dynamodb

Create DynamoDB table with Global Secondary Index


I'm new to AWS DynamoDB and to nosql in general, and I'm having problem with table creation.

I'm trying to create a table named User with the following Attributes:

  • UserId (HASH)
  • OSType (RANGE)
  • MSISDN
  • IMSI
  • DeviceID

I need to query the table not only by UserId, but also by the following fields:

  • MSISDN
  • IMSI
  • DeviceID

My Logic is as follows:

  1. Query the table by the UserId field.
  2. If the query returned no results create a new one, but check that there isn't other users with the same MSISDN filed OR the same IMSI field OR the same DeviceID field.

After reading the manual about LSI/GSI i'm having difficulties understating how to create the table and define those indexes.

This is the code i'm tring to execute to creater the table using PHP+AWS SDK:

    $client->createTable(array(
    'TableName' => 'User',
    'AttributeDefinitions' => array(
        array('AttributeName' => 'UserId',      'AttributeType' => 'S'),
        array('AttributeName' => 'OSType',      'AttributeType' => 'S'),
        array('AttributeName' => 'MSISDN',      'AttributeType' => 'S'),
        array('AttributeName' => 'IMSI',        'AttributeType' => 'S'),
        array('AttributeName' => 'DeviceID',    'AttributeType' => 'S'),
    ),
    'KeySchema' => array(
        array('AttributeName' => 'UserId', 'KeyType' => 'HASH'),
        array('AttributeName' => 'OSType', 'KeyType' => 'RANGE')
    ),
    'GlobalSecondaryIndexes' => array(
        array(
            'IndexName' => 'IMSIIndex',
            'KeySchema' => array(
                array('AttributeName' => 'IMSI',    'KeyType' => 'HASH')
            ),
            'Projection' => array(
                'ProjectionType' => 'KEYS_ONLY',
            ),
            'ProvisionedThroughput' => array(
                'ReadCapacityUnits'  => 10,
                'WriteCapacityUnits' => 10
            )
        ),
        array(
            'IndexName' => 'MSISDNIndex',
            'KeySchema' => array(
                array('AttributeName' => 'MSISDN',  'KeyType' => 'HASH')
            ),
            'Projection' => array(
                'ProjectionType' => 'KEYS_ONLY',
            ),
            'ProvisionedThroughput' => array(
                'ReadCapacityUnits'  => 10,
                'WriteCapacityUnits' => 10
            )
        ),
        array(
            'IndexName' => 'DeviceIDIndex',
            'KeySchema' => array(
                array('AttributeName' => 'DeviceID',    'KeyType' => 'HASH')
            ),
            'Projection' => array(
                'ProjectionType' => 'KEYS_ONLY',
            ),
            'ProvisionedThroughput' => array(
                'ReadCapacityUnits'  => 10,
                'WriteCapacityUnits' => 10
            )
        ),
    ),
    'ProvisionedThroughput' => array(
        'ReadCapacityUnits'  => 50,
        'WriteCapacityUnits' => 50
    )
));

I'm getting this error:

PHP Fatal error:  Uncaught Aws\DynamoDb\Exception\ValidationException: AWS Error Code: ValidationException, Status Code: 400, AWS Request ID: 70LGIARTTQF90S8P0HVRUKSJ27VV4KQNSO5AEMVJF66Q9ASUAAJG, AWS Error Type: client, AWS Error Message: One or more parameter values were invalid: Number of attributes in KeySchema does not exactly match number of attributes defined in AttributeDefinitions, User-Agent: aws-sdk-php2/2.4.11 Guzzle/3.7.4 curl/7.29.0 PHP/5.4.14

Please help me understand what am I doing wrong. I want to create the table with GSI, but I just can't comprehend the essence of secondary index in DynamoDB :(


Solution

  • This should work:

    $client->createTable(array(
    'TableName' => 'User',
    'AttributeDefinitions' => array(
        array('AttributeName' => 'UserId',      'AttributeType' => 'S'),
        array('AttributeName' => 'OSType',      'AttributeType' => 'S')
    ),
    'KeySchema' => array(
        array('AttributeName' => 'UserId', 'KeyType' => 'HASH'),
        array('AttributeName' => 'OSType', 'KeyType' => 'RANGE')
    ),
    'GlobalSecondaryIndexes' => array(
        array(
            'IndexName' => 'IMSIIndex',
            'KeySchema' => array(
                array('AttributeName' => 'IMSI',    'KeyType' => 'HASH')
            ),
            'Projection' => array(
                'ProjectionType' => 'KEYS_ONLY',
            ),
            'ProvisionedThroughput' => array(
                'ReadCapacityUnits'  => 10,
                'WriteCapacityUnits' => 10
            )
        ),
        array(
            'IndexName' => 'MSISDNIndex',
            'KeySchema' => array(
                array('AttributeName' => 'MSISDN',  'KeyType' => 'HASH')
            ),
            'Projection' => array(
                'ProjectionType' => 'KEYS_ONLY',
            ),
            'ProvisionedThroughput' => array(
                'ReadCapacityUnits'  => 10,
                'WriteCapacityUnits' => 10
            )
        ),
        array(
            'IndexName' => 'DeviceIDIndex',
            'KeySchema' => array(
                array('AttributeName' => 'DeviceID',    'KeyType' => 'HASH')
            ),
            'Projection' => array(
                'ProjectionType' => 'KEYS_ONLY',
            ),
            'ProvisionedThroughput' => array(
                'ReadCapacityUnits'  => 10,
                'WriteCapacityUnits' => 10
            )
        ),
    ),
    'ProvisionedThroughput' => array(
        'ReadCapacityUnits'  => 50,
        'WriteCapacityUnits' => 50
    )));
    

    Hope that helps