DynamoDB - How to query a nested attribute boto3

12,438

Solution 1

You can use contains to filter the data from List data type.

genres -attribute stored as List inside info attribute which is a Map data type

FilterExpression=Attr('info.genres').contains('Drama')

Solution 2

Unlike in the accepted answer, to be able to filter all the items with the attribute, you need to use scan() instead of query(). query() requires KeyCondition which is unnecessary in your case and forces you to create condition containing f.e. year.

Therefore

table.scan(FilterExpression=Attr('info.genres').contains('Drama'))

should do the job

Share:
12,438
Dalton Sweeney
Author by

Dalton Sweeney

Updated on June 09, 2022

Comments

  • Dalton Sweeney
    Dalton Sweeney almost 2 years

    I am following the DynamoDB python tutorial. This step shows how to query the table based on a specific key: http://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/GettingStarted.Python.04.html.

    Here is the code for this query:

    from __future__ import print_function # Python 2/3 compatibility
    import boto3
    import json
    import decimal
    from boto3.dynamodb.conditions import Key, Attr
    
    # Helper class to convert a DynamoDB item to JSON.
    class DecimalEncoder(json.JSONEncoder):
        def default(self, o):
            if isinstance(o, decimal.Decimal):
                return str(o)
            return super(DecimalEncoder, self).default(o)
    
    dynamodb = boto3.resource('dynamodb', region_name='us-west-2', endpoint_url="http://localhost:8000")
    
    table = dynamodb.Table('Movies')
    
    print("Movies from 1992 - titles A-L, with genres and lead actor")
    
    response = table.query(
        ProjectionExpression="#yr, title, info.genres, info.actors[0]",
        ExpressionAttributeNames={ "#yr": "year" }, # Expression Attribute Names for Projection Expression only.
        KeyConditionExpression=Key('year').eq(1992) & Key('title').between('A', 'L')
    )
    
    for i in response[u'Items']:
        print(json.dumps(i, cls=DecimalEncoder))
    

    An example response item is

    {
        "title": "Juice",
        "year": "1992",
        "info": {
            "actors": [
                "Omar Epps"
            ],
            "genres": [
                "Crime",
                "Drama",
                "Thriller"
            ]
        }
    }
    

    The table has the two key attributes 'title' and 'year' as well as the nested attribute 'info'. What I am trying to do is query the database and filter the movies by genre, for example get all Drama movies. I am not sure how to do this since the genre key is nested inside info.

    I tried to get all the Drama movies from 1992 like this but it came up blank.

    response = table.query(
        KeyConditionExpression=Key('year').eq(1992),
        FilterExpression=Attr('info.genres').eq('Drama')
    )
    

    How do I properly filter this query with the nested info attribute?