skip to Main Content

enter image description here

I want to get only timestamp, address, distance, and proximity from DynamoDB using Lambda function, so that I can get the response at API Gateway to display on my React Native app.
May I know what’s wrong with my Lambda function code?

import boto3
import json

from boto3.dynamodb.conditions import Key, Attr

def lambda_handler(event, context):

    IRAPID_BEACON = 'irapid_beacon'
    
    DDB_RESOURCE = boto3.resource('dynamodb')
    IRAPID_BEACON_DDB_TABLE = DDB_RESOURCE.Table(IRAPID_BEACON)
    
    result = IRAPID_BEACON_DDB_TABLE.get_item(Key={'timestamp'}, ProjectionExpression='#timestamp, address, distance, proximity', ExpressionAttributeNames={'#address': 'address'})
    
    return {
        'body': result
    }

This is the response I get:

{
  "errorMessage": "Parameter validation failed:nInvalid type for parameter Key, value: {'timestamp'}, type: <class 'set'>, valid types: <class 'dict'>",
  "errorType": "ParamValidationError",
  "requestId": "3af15dff-d323-49bf-9429-bfce2d26e579",
  "stackTrace": [
    "  File "/var/task/lambda_function.py", line 14, in lambda_handlern    result = IRAPID_BEACON_DDB_TABLE.get_item(Key={'timestamp'}, ProjectionExpression='#timestamp, address, distance, proximity', ExpressionAttributeNames={'#address': 'address'})n",
    "  File "/var/runtime/boto3/resources/factory.py", line 520, in do_actionn    response = action(self, *args, **kwargs)n",
    "  File "/var/runtime/boto3/resources/action.py", line 83, in __call__n    response = getattr(parent.meta.client, operation_name)(*args, **params)n",
    "  File "/var/runtime/botocore/client.py", line 391, in _api_calln    return self._make_api_call(operation_name, kwargs)n",
    "  File "/var/runtime/botocore/client.py", line 691, in _make_api_calln    request_dict = self._convert_to_request_dict(n",
    "  File "/var/runtime/botocore/client.py", line 739, in _convert_to_request_dictn    request_dict = self._serializer.serialize_to_request(n",
    "  File "/var/runtime/botocore/validate.py", line 360, in serialize_to_requestn    raise ParamValidationError(report=report.generate_report())n"
  ]
}

3

Answers


  1. Chosen as BEST ANSWER

    I solved my problem by this:

    import boto3
    import json
    
    from boto3.dynamodb.conditions import Key, Attr
        
    def lambda_handler(event, context):
    
        dynamodb = boto3.client('dynamodb')
        
        IRAPID_BEACON = 'irapid_beacon'
        DDB_RESOURCE = boto3.resource('dynamodb')
        IRAPID_BEACON_TABLE = DDB_RESOURCE.Table(IRAPID_BEACON)
        
        projection_expression = '#attr1, #attr2, #attr3, #attr4'
        
        expression_attribute_names = {
            '#attr1': 'timestamp',
            '#attr2': 'address',
            '#attr3': 'distance',
            '#attr4': 'proximity',
        }
        
        scan_params = {
            'TableName': IRAPID_BEACON,
            'ProjectionExpression': projection_expression,
            'ExpressionAttributeNames': expression_attribute_names
        }
    
        response = dynamodb.scan(**scan_params)
        
        data = response['Items']
        while 'LastEvaluatedKey' in response:
            response = IRAPID_BEACON_TABLE.scan(ExclusiveStartKey=response['LastEvaluatedKey'])
            data.extend(response['Items'])
            
        return data
    

    The result I got:

    [
      {
        "proximity": {
          "S": "IMMEDIATE"
        },
        "address": {
          "S": "E3:60:15:DA:38:E2"
        },
        "distance": {
          "N": "0.013031512640464739"
        },
        "timestamp": {
          "N": "1679536528228"
        }
      },
      {
        "proximity": {
          "S": "FAR"
        },
        "address": {
          "S": "C7:EE:CA:83:FA:AC"
        },
        "distance": {
          "N": "60.536073313879164"
        },
        "timestamp": {
          "N": "1679476131297"
        }
      }, ...]
    

  2. As suggested by the error message, you should specify a value in your Key parameter:

    Key={'timestamp': '1680332401551'}
    
    Login or Signup to reply.
  3. I suggest that you take a deep dive into DynamoDB documentation. I don’t believe your data model will do what you expect.

    If you want to do a GetItem you must provide the value of the partition key, in your case the timestamp.

    Key={'timestamp': '<some time stamp value>'}
    

    Its important to note that having timestamp as the partition key provides you very little query flexibility, it is also an issue if 2 items are written at the same time, one item would overwrite the other.

    With your current schema, you would need to do a Scan with a FilterExpression which would be highly inefficient.

    My suggestion depending on your throughput would be to use a static partition key value and timestamp as sort key. This will allow you do things like "give me all the items between this time range" or "give me the item at this specific time"

    PK SK data
    1 1680332401000 other
    1 1680332412345 other
    1 1680332402222 other

    Using Query you can now do things like:

    SELECT * FROM mytable WHERE PK=1 AND SK > 1680332401000
    

    Note that this would assume you do not write to the table more than 1000 RPS. If you do, then you would need to shard the PK by #no of reqs/1000.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search