1

The following code produces this error message when trying to access my AWS DynamoDB table. The table is called customers and the column is called email with a value of '[email protected]'. I've copied this code straight out of AWS examples available here https://github.com/awsdocs/aws-doc-sdk-examples. Is there anything I'm doing wrong? I've wasted days on this, trying different things :-(

Any help appreciated. Thanks,

Error message

{"message":"Expected params.Key to be a map","code":"InvalidParameterType","time":"2019-03-13T23:05:59.231Z"}

NodeJs code

const express = require('express')
const app = express()
const port = 8080
var AWS = require('aws-sdk');

app.get('/test', (req, res) => {

    // Set the region 
    AWS.config.update({region: 'eu-west-1'});

    // Create DynamoDB document client
    var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});

    var key = { email: '[email protected]' };

    ddb.getItem({
       TableName: 'customers',
       Key: key
    }, function(err, data) {
        if (err) {
          res.send(err);
        }
        else {
          res.send(data);
        }
    });

});

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

DynamoDB table

enter image description here

Another attempt I've also received this error message

{"message":"There were 20 validation errors:\n* InvalidParameterType: Expected params.Key['email'] to be a structure\n* UnexpectedParameter: Unexpected key '0' found in params.Key['email']\n* UnexpectedParameter: Unexpected key '1' found in params.Key['email']\n* UnexpectedParameter: Unexpected key '2' found in params.Key['email']\n* UnexpectedParameter: Unexpected key '3' found in params.Key['email']\n* UnexpectedParameter: Unexpected key '4' found in params.Key['email']\n* UnexpectedParameter: Unexpected key '5' found in params.Key['email']\n* UnexpectedParameter: Unexpected key '6' found in 

Update

 var key = { email: '[email protected]' };

    ddb.getItem({
       TableName: 'customers',
       Key: key
    }, function(err, data) {
        if (err) {
          res.send(err);
        }
        else {
          res.send(data);
        }
    });

Update

const express = require('express')
const app = express()
const port = 8080
var AWS = require('aws-sdk');

app.get('/test', (req, res) => {

    AWS.config.update({region: 'eu-west-1'});
    var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});

    var params = {
      TableName: 'customers',
      Key: {
        'email': {S: '[email protected]'}
      },
    };

    ddb.getItem(params, function(err, data) {
        if (err) {
            res.send(err);
        } else {
            res.send(data);
        }
    });

});

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

Error result

{"message":"The provided key element does not match the schema","code":"ValidationException","time":"2019-03-14T19:26:13.602Z","requestId":"EIGKLLNEJR2DKSET6787JHQLC7VV4KQNSO5AEMVJF66Q9ASUAAJG","statusCode":400,"retryable":false,"retryDelay":46.10177725769697}
1
  • I have completely missed that you are not using DocumentClient but DynamoDB service. Check updated answer Commented Mar 14, 2019 at 13:20

2 Answers 2

3

2nd EDIT : I have completely missed that you are not using DocumentClient (as pointed out Vladyslav Ulenko), so updated answer below for completeness.


You have two options:

First option use DynamoDB service object with getItem method like this:

...
var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});

var params = {
  TableName: 'customers',
  Key: {
    'email': {S: '[email protected]'} . // <-- pay attention to data type 'S'  
  },
};

ddb.getItem(params, function(err, data) {
    if (err) {
        res.send(err);
    } else {
        res.send(data);
    }
});

DynamoDB Data (attribute value) types are specified here (look for table Marshalling/Unmarshalling mapping.

Second option is to use DocumentClient. In this scenario you don't have to worry about marshaling and un-marshaling request/response data (DynamoDB value to/from JavaScript type). In this case your code is like this:

...

var docClient = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});


var params = {
 TableName: 'customers',
 Key: {'email': '[email protected]'}
};

docClient.get(params, function (err, data) {
    if (err) {
        res.send(err);
    } else {
        res.send(data);
    }
});
...

I would suggest you go with the DocumentClient instead of DynamoDB'getItem` operation as it completely handles all data conversion!

If you don't you would ALSO need to take care of response data types, eg:

data.Items.forEach(function(element, index, array) {
      console.log(element.FristName.S + " " + element.LastName.S);
    });

not sure if you want to that


3rd EDIT : Now that you have done the above you are getting error:

"The provided key element does not match the schema"

This means that the Key you used is not the same as the key defined on your schema, again from documentation:

For the primary key, you must provide all of the attributes. For example, with a simple primary key, you only need to provide a value for the partition key. For a composite primary key, you must provide values for both the partition key and the sort key.

Check the keys on your Table Details (example) enter image description here

and make sure you put all keys mentioned there in your key parameter

Again as Vladyslav pointed out in comment section of his answer, if you need to find an item using the attribute that is not your primary key, you need to use scan operation instead of getItem. You can find sample in documentation

Sign up to request clarification or add additional context in comments.

10 Comments

made this change (see update in question) but still experiencing an error?
James - you are still missing data type - as you are using DynamoDB service and not DocumentClient. Updated answer for completeness
I'm trying now, I've updated the question with what I've tried (option 1 with AWS.DynamoDB) but I get the error "The provided key element does not match the schema"
@James - that is new issue :) keep updating your question is going to be very confusing for people to follow btw... Updating Answer
That means that in your database in order to find 'by' email you need to use scan operation, get can only be used with Primary Key - in your case id
|
1

You are using DynamoDB like DocumentClient. If you switch your line var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'}); to var docClient = new AWS.DynamoDB.DocumentClient();, your queries will work.

With plain DynamoDB class instance you should also specify data types of your keys manually, you can find the reference to data types here. However, with DocumentClient class instance, the very class is responsible for data mapping between JS types and DynamoDB types. You can find this info here in the Overview section.

8 Comments

You are right I've completely missed that he is not using DocumentClient but DynamoDB service. I have updated my answer for completeness as I see he is still missing some things...
I've made the change (see latest update in my question) but I get an error?
Now it looks like your query is wrong. Does your primary key consist of partition key and range key, or only partition key?
Also, keep in mind that with DynamoDB you can get only over a partition key. For everything else you should use scan or better global secondary index on some field and query over it
I see. Then your option is to put a GSI over email, if you are going to query over it a lot. DynamoDB is a very quirky database - keep that in mind. If your request can't be fulfilled with query or getItem, you are forced to use scan, which is very expensive. Design your schemes carefully and you're going to have a nice performance and small bill :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.