Search code examples
node.jsamazon-s3aws-lambdaserverlessaws-serverless

To retrieve Employee Details by using gsikey from dynamo db in AWS ServerLess


I want to retieve Employee details from dynamoDb using GSI Key. Here I have a table which depicts a relation between employee and departments, I would like to get an employee details by using employeeId. Serverless Template Given below

    service: dynaUser

custom:
  settings:
    POSTS_TABLE: Tbl-tblMasterDepartmentEmp1
provider:
  name: aws
  runtime: nodejs10.x
  region: ap-northeast-1
  environment: ${self:custom.settings}
  
  iamRoleStatements:
   - Effect: "Allow"
     Action:
        - dynamodb:Query
        - dynamodb:DescribeTable
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
     Resource:
      - "arn:aws:dynamodb:${self:provider.region}:*:table/${self:custom.settings.POSTS_TABLE}"      
   - Effect: Allow
     Action:
        - dynamodb:Query
        - dynamodb:Scan
     Resource: 
      - "arn:aws:dynamodb:${self:provider.region}:*:table/${self:custom.settings.POSTS_TABLE}/index/*"
functions:
  createPost:
    handler: handler.createPost
    events:
    - http:
        path: /createEmployee
        method: post
        # integration: lambda
        # request:
        #   passThrough: NEVER
  createDepartment:
    handler: handler.createDepartmententry
    events:
    - http:
        path: /createDepartment
        method: post
        # integration: lambda
        # request:
        #   passThrough: NEVER        
  getEmpDataByID:
    handler: handler.getEmployeeDetails
    events:
    - http:
        path: /getemployee/{id}
        method: get
  getEmpDataByDeptID:
    handler: handler.getEmployeeDetailsByDeptId
    events:
    - http:
        method: get
        path: /getemployeeByDept
        integration: lambda
        request:
          template:
            application/json: '{ "deptId" : "$input.params(''deptId'')" }'  
resources:
  Resources:
    PostsTable:
      Type: AWS::DynamoDB::Table
      Properties:
        AttributeDefinitions:
        - AttributeName: Pk_id
          AttributeType: "S"  
        - AttributeName: Sk_id
          AttributeType: "S"  
        - AttributeName: cat_type
          AttributeType: "S"  
        KeySchema:
        - AttributeName: "Pk_id"
          KeyType: "HASH"
        - AttributeName: "Sk_id"
          KeyType: "RANGE"
        TableName: ${self:custom.settings.POSTS_TABLE}
        GlobalSecondaryIndexes:
          - IndexName: empIdIndex
            KeySchema:
              - AttributeName: cat_type
                KeyType: HASH
              - AttributeName: Sk_id
                KeyType: RANGE
            Projection:
              ProjectionType: 'ALL'
        TimeToLiveSpecification:
          AttributeName: ttl
          Enabled: true
        BillingMode: PAY_PER_REQUEST

also used query to retrieve employee Data from Db and Given below

// Get employee Details by using Id

module.exports.getEmployeeDetails = (event, context, callback) => {
  const id = event.pathParameters.id;
  const params = {
    Key: {
      Sk_id: id,
      type:"Stud"
    },
    TableName: deptTable,
    IndexName:"empIdIndex"
  };

  return db
    .get(params)
    .promise()
    .then((res) => {
      if (res.Item) callback(null, response(200, res.Item));
      else callback(null, response(404, { error: 'Post not found' }));
    })
    .catch((err) => callback(null, response(err.statusCode, err)));
};

  here I inclued error like

 {
    "message": "The provided key element does not match the schema",
    "code": "ValidationException",
    "time": "2020-12-09T17:27:24.439Z",
    "requestId": "E4QR1ITHPKNE7TQDS6S7R211O7VV4KQNSO5AEMVJF66Q9ASUAAJG",
    "statusCode": 400,
    "retryable": false,
    "retryDelay": 22.385564476989238
}

How can I retrieve item from dynamodb with out any error ,and I am new to the aws world?


Solution

  • Check the error message:

    Invalid KeyConditionExpression: Attribute name is a reserved keyword; reserved keyword: type

    DynamoDB is telling you that your KeyCondition uses a reserved keyword called type. The full list of reserved keywords is documented here.

    Now look at your KeyConditionExpression:

    'emp_id = :emp_id AND type = :type '
    

    Note: There is also whitespace at the end of this expression.

    You have two options to fix this:

    1. Change the name of the attribute.
    2. Use ExpressionAttributeNames to "rename" the attribute in the query.

    Option 1 is self explaining, option 2 should probably look like this:

    const params = {
        KeyConditionExpression: 'emp_id = :emp_id AND #employeeType = :type',
        ExpressionAttributeNames: { 
            "#employeeType": "type" 
        },
        ExpressionAttributeValues: {
            ':emp_id': {'S': '1'},
            ':type':{'S':'Stud'}
        },
        TableName: deptTable,
        IndexName:"empIdIndex"   
    };
    

    Two things changed:

    1. The KeyConditionExpression now uses a "placeholder" attribute name called #employeeType (the # appears to be a common DynamoDB convention) instead of the reserved keyword type.
    2. There is now a "mapping" between the placeholder name #employeeType and the actual attribute name type in ExpressionAttributeNames.

    Personally, I'd recommend not using a reserved keyword as attribute name (option 1).