Event Driven Programming with Amazon DynamoDB and AWS Lambda

Introduction

In this article, we will learn about a different event driven programming method with DynamoDB and Lambda.

Solution Diagram

The diagram is very simple, we just demonstrate how to use lambda to trigger the update in DynamoDB. We will pass through a JSON into the Lambda function,, then create an item in DyanmoDB.

Create Tables in DyamoDB

In DynamoDB page, we click “Create table”.

Please type GameScoreRecords as table name and RecordID as primary key, and select Number as primary key type. Please follow my exact name here, otherwise you may need to edit the lambda function code.

Also create one more table, please type GameScoresByUser as table name and Username as primary key, and select String as primary key type.

Select GameScoreRecords table, Click “Manage DynamoDB stream”, and select “New image – the entire item, as it appears after it was modified”. Finally click “Enable”.

In this way, any record sent to this table will now send a message via DynamoDB streams, which can trigger a Lambda function.

Create a Lambda Function

In AWS Lambda page, click create function.

We just type the function name as UpdateScore, then create a new role for Lambda permissions.

Then click create function.

We go to IAM page, since the created new rule has not enough to access DynamoDB, click Roles and select our roles.

Click Attach policies.

Select DynamoDBFullAccess, then attach policy.

Back to our Lambda function now. Once we create a Lambda function, please paste below code into the index.js file like above figure and click deploy.

// Set up AWS client
var AWS = require('aws-sdk');
var dynamodb = new AWS.DynamoDB();

exports.handler = function(event, context) {
    // Keep track of how many requests are in flight
    var inflightRequests = 0;

    event.Records.forEach(function(record) {
        console.log('DynamoDB Record: %j', record.dynamodb);
        // Get the new image of the DynamoDB Streams record
        var newItemImage = record.dynamodb.NewImage;

        // Set the appropriate parameters for UpdateItem
        // Refer to the ADD operation in the UpdateItem API for UpdateExpression
        // http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html
        // Adds the specified value to the item, if attribute does not exist, set the attribute
        var updateItemParams = {
            TableName: "GameScoresByUser",
            Key : { Username : newItemImage.Username },
            UpdateExpression : 'ADD Score :attrValue',
            ExpressionAttributeValues : {':attrValue' : newItemImage.Score}
        }

        // Make a callback function to execute once UpdateItem request completes
        // It may be helpful to refer to the updateItem method for the Javascript SDK
        // http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html\#updateItem-property
        var updateItemCallback = function(err, data) {
            if (err) {
                // log errors
                console.log(err, err.stack);
            } else {
                // check if all requests are finished, if so, end the function
                inflightRequests--;
                if (inflightRequests === 0) {
                    context.succeed("Successfully processed " + event.Records.length + " records.");
                }
            }
        };

        // Send UpdateItem request to DynamoDB
        dynamodb.updateItem(updateItemParams, updateItemCallback);
        // Increase count for number of requests in flight
        inflightRequests++;
        });

        // If there are no more requests pending, end the function
        if (inflightRequests === 0) {
            context.succeed("Successfully processed " + event.Records.length + " records.");
        }
    };

In Designer, we click “Add trigger”.

Select DynamoDB and choose the GameScoreByUser table as we created previously. Then click Add.

It shows success message. The function will not be triggered when a new game score is added to the DynamoDB table. We can now test the function with a record that simulates an update of the database.

We click Test now.

Type the event name, paste below code and click create.

{
  "Records": [
    {
      "eventID": "1",
      "eventVersion": "1.0",
      "dynamodb": {
        "Keys": { "RecordID": {"S": "2" }
      },
      "NewImage": {
        "RecordID": {"S": "2" },
        "Username": { "S": "Jane Doe" },
        "Score": { "N": "100" },
        "Nickname": { "S": "JaneD" }
      },
      "StreamViewType": "NEW_IMAGE",
      "SequenceNumber": "111",
      "SizeBytes": 26
    },
    "awsRegion": "us-west-2",
    "eventName": "INSERT",
    "eventSourceARN": "arn:aws:dynamodb:us-west-2:account-id:table/GameScoreRecords/stream/2015-10-07T00:48:05.899",
    "eventSource": "aws:dynamodb"
    }
  ]
}

Now we simply click “Test”.

It shows success message that we update our table successfully.

Testing

Back to DynamoDB, select GameScoreByUser table, we can see an item is updated in items tab.

Select GameScoreRecords and create item.

We can try to input some random values for RecordID, Username and Score by click “+” and Append String for Username and Number for Score. Finally click save.

Now we are able to see a new record is created.

Cleanup

Delete these two tables.

Delete the Lambda function.

Leave a Reply