CCCC
CCCC

Reputation: 6451

aws - how to set lambda function to make dynamic query to dynamodb

This is my current lambda function, which return all data from Table "Banner".

getBanner.js

'use strict'
const AWS = require('aws-sdk');

exports.handler = async function (event, context, callback) {
    const documentClient = new AWS.DynamoDB.DocumentClient();

    let responseBody = "";
    let statusCode = 0;

    const params = {
        TableName : "Banner",
    };

    try{
        const data = await documentClient.scan(params).promise();
        responseBody = JSON.stringify(data.Items);
        statusCode = 200
    }catch(err){
        responseBody = `Unable to get products: ${err}`;
        statusCode = 403
    }

    const response = {
        statusCode: statusCode,
        headers:{
            "Content-Type": "application/json",
            'Access-Control-Allow-Origin': '*', // Required for CORS support to work
        },
        body: responseBody
    }

    return response
}

It is the sample returned data

[
   {
       Order: 123,
       Year: 2000
       ...
   },
   {
       Order: 77,
       Year: 2007
       ...
   }
]

I understand If I want to do some query for attribute order, I need to change to following.

...
var params = {
    TableName : "Banner",
    KeyConditionExpression: "#od = :yyyy",
    ExpressionAttributeNames:{
        "#od": "order"
    },
    ExpressionAttributeValues: {
        ":yyyy": 1
    }
};
...

What if I want to do the following?
enter image description here There may be some use cases which make me need to do query for another attribute, or multiple attributes.

How should I do have a function which can handle the queryStringParameters dynamically?

Updated based on the comment, but another error occurs

'use strict'
const AWS = require('aws-sdk');

exports.handler = async function (event, context, callback) {
    const documentClient = new AWS.DynamoDB.DocumentClient();

    let responseBody = "";
    let statusCode = 0;

    console.log(event)
    const queryStringParams = event.queryStringParameters;

    console.log(queryStringParams)

    let KeyConditionExpression = ''
    let ExpressionAttributeNames={};
    let ExpressionAttributeValues = {};
    for (const property in queryStringParams) {
      KeyConditionExpression += ` #${property} = :${property} ,`;
      ExpressionAttributeNames['#'+property] = property ;
      ExpressionAttributeValues[':'+property]=queryStringParams[property];
    }

    KeyConditionExpression= KeyConditionExpression.slice(0, -1);

    const params = {
        TableName : "Banner",
        KeyConditionExpression: KeyConditionExpression,
        ExpressionAttributeNames: ExpressionAttributeNames,
        ExpressionAttributeValues: ExpressionAttributeValues
    };

    console.log(params)   //Response A

    try{
        const data = await documentClient.scan(params).promise();
        responseBody = JSON.stringify(data.Items);
        statusCode = 200
    }catch(err){
        responseBody = `Unabel to get products: ${err}`;
        statusCode = 403
    }

    const response = {
        statusCode: statusCode,
        headers:{
            "Content-Type": "application/json",
            'Access-Control-Allow-Origin': '*', // Required for CORS support to work
        },
        body: responseBody
    }

    return response
}
Unabel to get products: ValidationException: ExpressionAttributeNames can only be specified when using expressions

This is the value of the ‘params’ obtained from cloudwatch Response A

{
  TableName: 'Banner',
  KeyConditionExpression: ' #order = :order , #year = :year ',
  ExpressionAttributeNames: { '#order': 'order', '#year': 'year' },
  ExpressionAttributeValues: { ':order': '1', ':year': '2007' }
}

Upvotes: 1

Views: 2141

Answers (3)

utsav sharma
utsav sharma

Reputation: 21

Use FilterExpression when using scan instead of KeyConditionExpression. Sample

const queryStringParams = event.queryStringParameters;
  let FilterExpression = "";
  let ExpressionAttributeNames = {};
  let ExpressionAttributeValues = {};
  for (const property in queryStringParams) {
    FilterExpression += ` #${property} = :${property} ,`;
    ExpressionAttributeNames["#" + property] = property;
    ExpressionAttributeValues[":" + property] = queryStringParams[property];
  }

  FilterExpression = FilterExpression.slice(0, -1);
  

  const params = {
    TableName: tableName,
    FilterExpression: FilterExpression,
    ExpressionAttributeNames: ExpressionAttributeNames,
    ExpressionAttributeValues: ExpressionAttributeValues
  };

Upvotes: 2

Hossam ELMansy
Hossam ELMansy

Reputation: 516

You can this query parameters from the event object in your Lambda function handler. The event object content depends on what service invoked the Lambda function. If Lambda function invoked from Elastic Load Balancing or from API gateway you can get the query parameters from the event object. The event object will have an attribute called queryStringParameters which have all the query string parameters in the request.

This is a sample for an event object from the documentation:

{
    "requestContext": {
        "elb": {
            "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/lambda-279XGJDqGZ5rsrHC2Fjr/49e9d65c45c6791a"
        }
    },
    "httpMethod": "GET",
    "path": "/lambda",
    "queryStringParameters": {
        "query": "1234ABCD"
    },
    "headers": {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "accept-encoding": "gzip",
        "accept-language": "en-US,en;q=0.9",
        "connection": "keep-alive",
        "host": "lambda-alb-123578498.us-east-2.elb.amazonaws.com",
        "upgrade-insecure-requests": "1",
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
        "x-amzn-trace-id": "Root=1-5c536348-3d683b8b04734faae651f476",
        "x-forwarded-for": "72.12.164.125",
        "x-forwarded-port": "80",
        "x-forwarded-proto": "http",
        "x-imforwards": "20"
    },
    "body": "",
    "isBase64Encoded": false
}

https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html https://docs.aws.amazon.com/lambda/latest/dg/lambda-services.html

Example for your case: (NOTE: name of the query strings must be the same as expression attributes)

const queryStringParams = event.queryStringParams;
const updatedQueryStringParams = {};

Object.keys(queryStringParams).forEach(key => updatedQueryStringParams[`:${key}`] = queryStringParams[key]);

    var params = {
        TableName : "Banner",
        KeyConditionExpression: "#od = :year",
        ExpressionAttributeNames:{
            "#od": "order"
        },
        ExpressionAttributeValues: {
            ...updatedQueryStringParams
        }
    };

Upvotes: 1

CyberEternal
CyberEternal

Reputation: 2545

Simple example

const getParams = (key, value) => ({
  TableName: "Banner",
  KeyConditionExpression: "#key = :value",
  ExpressionAttributeNames: {
    "#key": key
  },
  ExpressionAttributeValues: {
    ":value": value
  }
});

And call this function based on your query parameters. Query parameters you can get from the event.

const queryParams = event.queryStringParameters;

Upvotes: 1

Related Questions