0

I built an AWS Lambda that scans and filters my DynamoDB and returns to my AWS API. Thereby I had three possible search parameters (itemname, author and type), whereas I don’t know which of them are used in a query. At first, I implemented a version, in which all search parameters where hard coded. As a result, I got errors if not all search parameters where defined. At the end I reworked the code to build individual scan params dependent on the inputted search parameter.

The code works fine, but I think that there are better implementations for this problem, maybe you can give me some improvement advice. Otherwise this will help people which face the same issues with their optional search parameters.

var AWS = require('aws-sdk');
var docClient = new AWS.DynamoDB.DocumentClient();

//This is the Lambda function
exports.handler = function(event, context, callback) 
{
//In case we query without query attributes
if(!event.hasOwnProperty("queryStringParameters"))
        {
            console.log("NO queryStringParameters FOUND");
            var emptyparams = 
                {  
                    TableName: "blackboard-items",
                };
            docClient.scan(emptyparams, onScan);
            return;
        }
        
//we want to tailor this attributes for the params for docClient.scan(params, onScan); 
var queryParam = event["queryStringParameters"];
var filterexpression = "";
var expressionAttributeNames = {}; //Instantiate
var expressionAttributeValues = {};
console.log("QUERY PARAMETERS: " + JSON.stringify(queryParam));
    
//Do we look for an author?
if(queryParam.hasOwnProperty("author"))
    {
        console.log("FOUND AUTHOR");
        filterexpression += "contains(#author, :author)"; //Collect scan params
        expressionAttributeNames['#author'] = 'author';
        expressionAttributeValues[':author'] = event["queryStringParameters"]["author"];
    }
    
//Do we look for an itemname?
if(queryParam.hasOwnProperty("itemname"))
    {
    console.log("FOUND ITEMNAME");
    if(filterexpression !== "")
        filterexpression += " AND contains(#itemname, :itemname)";
    else
        filterexpression += "contains(#itemname, :itemname)";
        
    expressionAttributeNames['#itemname'] = 'itemname';
    expressionAttributeValues[':itemname'] = queryParam["itemname"];    
    }
    
//Do we look for a type?
if(queryParam.hasOwnProperty("type"))
    {
    console.log("FOUND TYPE");
    if(filterexpression !== "")
        filterexpression += " AND #type = :type";
    else
        filterexpression += "#type = :type";
        
    expressionAttributeNames['#type'] = 'type';
    expressionAttributeValues[':type'] = event["queryStringParameters"]["type"]; 
    }
  
//Build params based on the tailored parts
var params = 
    {  
        TableName: "blackboard-items",
        FilterExpression: filterexpression,
        ExpressionAttributeNames: expressionAttributeNames,
        ExpressionAttributeValues: expressionAttributeValues,
    };
  
//Use tailored params for scan()
docClient.scan(params, onScan);
var count = 0;

function onScan(err, data)
    {
       if (err) 
        {
        console.error("Unable to scan the table. Error JSON:", JSON.stringify(err, null, 2));
        } 
        else 
        {        
        console.log("Scan succeeded.");
        data.Items.forEach(function(itemdata) 
            {
               console.log("Item :", ++count,JSON.stringify(itemdata));
            });

            // continue scanning if we have more items
            if (typeof data.LastEvaluatedKey != "undefined") 
            {
                console.log("Scanning for more...");
                params.ExclusiveStartKey = data.LastEvaluatedKey;
                docClient.scan(params, onScan);
            }
        }
        
        
    var response = 
    {
    "isBase64Encoded": false,
    "statusCode": "200",
    "headers": {  },
    "body": JSON.stringify(data.Items)
    };
 
    callback(null, response);
        
    }
 };

Note: The primary key of the DB is "itemname", but I will rework the DB design soon to have a sort key.

John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
  • You don't seem to have any actual problem. If you just want to share your code and get some comments on it then https://codereview.stackexchange.com/ might be the place for your. As I see it this post is off-topic on stackoverflow. – frido Feb 21 '19 at 10:56

1 Answers1

0

DynamoDB is very limited on its query capabilities and, as such, you should avoid scan at ALL costs. Every scan operation will consume your RCUs for every item it reads. If your table has many items, it can use up your RCUs quite quickly.

If you want to query by those 3 attributes, then DynamoDB may not be the best database for your use case. If you can narrow your query down to 1 attribute at a time instead, you can then use Global Secondary Indexes. That way you can query based on the author or type. You can see this answer on how to query for GSIs in DynamoDB

Thales Minussi
  • 6,965
  • 1
  • 30
  • 48