Neste módulo, você seguirá alguns exemplos simples de recuperação de vários itens em uma chamada de API com o DynamoDB. Também aprenderá a usar índices secundários para habilitar padrões de consulta adicionais nas suas tabelas do DynamoDB.

Tempo de conclusão do módulo: 15 minutos


No Módulo 2, você viu como recuperar um único livro de uma tabela do DynamoDB usando a chamada de API GetItem. Esse padrão de acesso é útil, mas seu aplicativo também precisa poder recuperar vários itens em uma chamada. Por exemplo, talvez você queira recuperar todos os livros que foram escritos por John Grisham, para poder exibi-los aos usuários. Na Etapa 1 deste módulo, você usará a API Query para recuperar todos os livros de um autor específico.

Tanto a chamada de API GetItem para obter um único livro e a chamada de API Query para recuperar todos os livros de um autor usam a chave primária especificada na sua tabela Books. No entanto, talvez você queira habilitar padrões de acesso adicionais, como recuperar todos os livros em uma categoria específica, por exemplo, história ou biografia. Category não faz parte da chave primária da sua tabela, mas você pode criar um índice secundário para permitir padrões de acesso adicionais. Você criará um índice secundário e o consultará nas Etapas 2 e 3 deste módulo.


  • Etapa 1. Recuperar vários itens com uma consulta

    Quando sua tabela usa uma chave primária composta, você pode recuperar todos os itens com a mesma chave de hash usando a chamada de API Query. Para o seu aplicativo, isso significa que é possível recuperar todos os livros com o mesmo atributo Author.

    No terminal AWS Cloud9, execute o comando a seguir.

    $ python query_items.py

    Esse comando executa o seguinte script, que recupera todos os livros escritos por John Grisham.

    import boto3
    from boto3.dynamodb.conditions import Key
    
    # boto3 is the AWS SDK library for Python.
    # The "resources" interface allows for a higher-level abstraction than the low-level client interface.
    # For more details, go to http://boto3.readthedocs.io/en/latest/guide/resources.html
    dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
    table = dynamodb.Table('Books')
    
    # When making a Query API call, you use the KeyConditionExpression parameter to specify the hash key on which you want to query.
    # You’re using the Key object from the Boto 3 library to specify that you want the attribute name ("Author")
    # to equal "John Grisham" by using the ".eq()" method.
    resp = table.query(KeyConditionExpression=Key('Author').eq('John Grisham'))
    
    print("The query returned the following items:")
    for item in resp['Items']:
        print(item)

    Depois de executar o script, você verá dois livros de John Grisham, The Firm e The Rainmaker.

    $ python query_items.py
    The query returned the following items:
    {'Title': 'The Firm', 'Formats': {'Hardcover': 'Q7QWE3U2', 'Paperback': 'ZVZAYY4F', 'Audiobook': 'DJ9KS9NM'}, 'Author': 'John Grisham', 'Category': 'Suspense'}
    {'Title': 'The Rainmaker', 'Formats': {'Hardcover': 'J4SUKVGU', 'Paperback': 'D7YF4FCX'}, 'Author': 'John Grisham', 'Category': 'Suspense'}

    A recuperação de vários itens com uma única chamada no DynamoDB é um padrão comum e fácil de executar com a chamada de API Query.

  • Etapa 2. Criar um índice secundário

    O DynamoDB permite criar índices secundários para levar em conta padrões de acesso a dados adicionais na sua tabela. Índices secundários são uma maneira poderosa de adicionar flexibilidade de consulta a uma tabela do DynamoDB.

    O DynamoDB tem dois tipos de índices secundários: índices secundários globais e índices secundários locais. Nesta seção, você adicionará um índice secundário global ao seu atributo Category, que permitirá recuperar todos os livros em uma categoria específica.

    O script de exemplo a seguir adiciona um índice secundário global a uma tabela existente.

    import boto3
    
    # Boto3 is the AWS SDK library for Python.
    # You can use the low-level client to make API calls to DynamoDB.
    client = boto3.client('dynamodb', region_name='us-east-1')
    
    try:
        resp = client.update_table(
            TableName="Books",
            # Any attributes used in your new global secondary index must be declared in AttributeDefinitions
            AttributeDefinitions=[
                {
                    "AttributeName": "Category",
                    "AttributeType": "S"
                },
            ],
            # This is where you add, update, or delete any global secondary indexes on your table.
            GlobalSecondaryIndexUpdates=[
                {
                    "Create": {
                        # You need to name your index and specifically refer to it when using it for queries.
                        "IndexName": "CategoryIndex",
                        # Like the table itself, you need to specify the key schema for an index.
                        # For a global secondary index, you can use a simple or composite key schema.
                        "KeySchema": [
                            {
                                "AttributeName": "Category",
                                "KeyType": "HASH"
                            }
                        ],
                        # You can choose to copy only specific attributes from the original item into the index.
                        # You might want to copy only a few attributes to save space.
                        "Projection": {
                            "ProjectionType": "ALL"
                        },
                        # Global secondary indexes have read and write capacity separate from the underlying table.
                        "ProvisionedThroughput": {
                            "ReadCapacityUnits": 1,
                            "WriteCapacityUnits": 1,
                        }
                    }
                }
            ],
        )
        print("Secondary index added!")
    except Exception as e:
        print("Error updating table:")
        print(e)

    O processo de criar um índice secundário global tem muito em comum com a criação de uma tabela. Você especifica um nome para o índice, os atributos que estarão no índice, o esquema de chaves do índice e a taxa de transferência provisionada (a capacidade máxima que um aplicativo pode consumir de uma tabela ou índice). A taxa de transferência provisionada em cada índice é separada da taxa de transferência provisionada em uma tabela. Isso permite que você defina uma taxa de transferência de maneira granular para atender às necessidades do seu aplicativo.

    Execute o seguinte comando no terminal para adicionar seu índice secundário global.

    $ python add_secondary_index.py

    Esse script adiciona um índice secundário global chamado CategoryIndex à sua tabela Books.

  • Etapa 3. Consultar um índice secundário

    Agora que você tem CategoryIndex, pode usá-lo para recuperar todos os livros com uma categoria específica. O processo de usar um índice secundário para consultar uma tabela é semelhante ao de usar a chamada de APIQuery. Agora, você adiciona o nome do índice à chamada de API.

    Quando um índice secundário global é adicionado a uma tabela existente, o DynamoDB preenche assincronamente esse índice com os itens existentes na tabela. O índice estará disponível para consulta após o preenchimento de todos os itens. O tempo de preenchimento varia de acordo com o tamanho da tabela.

    É possível usar o script query_with_index.py para consultar o novo índice. Execute o script com o seguinte comando no terminal.

    $ python query_with_index.py

    Esse comando executa o script a seguir para recuperar todos os livros em que Category é igual a Suspense.

    import time
    
    import boto3
    from boto3.dynamodb.conditions import Key
    
    # Boto3 is the AWS SDK library for Python.
    # The "resources" interface allows for a higher-level abstraction than the low-level client interface.
    # For more details, go to http://boto3.readthedocs.io/en/latest/guide/resources.html
    dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
    table = dynamodb.Table('Books')
    
    # When adding a global secondary index to an existing table, you cannot query the index until it has been backfilled.
    # This portion of the script waits until the index is in the “ACTIVE” status, indicating it is ready to be queried.
    while True:
        if not table.global_secondary_indexes or table.global_secondary_indexes[0]['IndexStatus'] != 'ACTIVE':
            print('Waiting for index to backfill...')
            time.sleep(5)
            table.reload()
        else:
            break
    
    # When making a Query call, you use the KeyConditionExpression parameter to specify the hash key on which you want to query.
    # If you want to use a specific index, you also need to pass the IndexName in our API call.
    resp = table.query(
        # Add the name of the index you want to use in your query.
        IndexName="CategoryIndex",
        KeyConditionExpression=Key('Category').eq('Suspense'),
    )
    
    print("The query returned the following items:")
    for item in resp['Items']:
        print(item)

    Observe que há uma parte do script que aguarda até que o índice esteja disponível para consulta.

    A seguinte saída será exibida no terminal:

    $ python query_with_index.py
    The query returned the following items:
    {'Title': 'The Firm', 'Formats': {'Hardcover': 'Q7QWE3U2', 'Paperback': 'ZVZAYY4F', 'Audiobook': 'DJ9KS9NM'}, 'Author': 'John Grisham', 'Category': 'Suspense'}
    {'Title': 'The Rainmaker', 'Formats': {'Hardcover': 'J4SUKVGU', 'Paperback': 'D7YF4FCX'}, 'Author': 'John Grisham', 'Category': 'Suspense'}
    {'Title': 'Along Came a Spider', 'Formats': {'Hardcover': 'C9NR6RJ7', 'Paperback': '37JVGDZG', 'Audiobook': '6348WX3U'}, 'Author': 'James Patterson', 'Category': 'Suspense'}

    A consulta retorna três livros de dois autores diferentes. Esse é um padrão de consulta que teria sido difícil com o esquema de chaves principal da sua tabela, mas que é fácil de implementar com o poder dos índices secundários.


    No próximo módulo, você aprenderá a atualizar os atributos de um item existente em uma tabela usando a API UpdateItem