AWS.DynamoDB.DocumentClient is not providing data on put - node.js

I am using the AWS.DynamoDB.DocumentClient, with Dynamodb local (port 8080). When I perform a put, the data variable in the callback is an empty object. Have I missed something?
import * as AWS from "aws-sdk";
AWS.config.update({
region: "us-west-2",
endpoint: "http://localhost:8080"
});
const docClient: any = new AWS.DynamoDB.DocumentClient();
const item = {
someField: "456",
other: "123"
};
const params = {
TableName: "TableName",
Item: item
};
docClient.put(params, function(err, data) {
if (err) console.log(err);
else console.log(data); // this produces: {}
});
There is no error, and the item is being inserted\updated - however the data variable is an empty object. Shouldn't this contain values?
Thanks

You aren't asking for any values to come back, so why do you expect there to be any values coming back? You'll need to set the appropriate parameters ReturnConsumedCapacity and/or ReturnItemCollectionMetrics and/or ReturnValues if you are wanting any of that to come back in the response.

As you can't set a value for "ReturnValues" that actually returns anything useful, I worked around it by simple passing back the original item data that was passed in.
import * as AWS from "aws-sdk";
AWS.config.update({
region: "us-west-2",
endpoint: "http://localhost:8080"
});
const docClient: any = new AWS.DynamoDB.DocumentClient();
const item = {
someField: "456",
other: "123"
};
const params = {
TableName: "TableName",
Item: item
};
// Have a clear reference to this scope
var self = this;
docClient.put(params, function(err, data) {
if (err) console.log(err);
else console.log(self.params.Item); // this should return the data you passed in!
});
I set "self" as "this" to make it clear where I'm reading the data from. Hope that helps someone!

To clarify accepted answer a bit.
Set the return value as:
var params = {
Item: data,
TableName: 'myTable',
ReturnValues: 'ALL_OLD'
}
The docs specify:
NONE - If ReturnValues is not specified, or if its value is NONE, then nothing is returned. (This setting is the default for ReturnValues.)
ALL_OLD - If PutItem overwrote an attribute name-value pair, then the content of the old item is returned.
Note: The ReturnValues parameter is used by several DynamoDB operations; however, PutItem does not recognize any values other than NONE or ALL_OLD.
This effectively means as the answer by Walter White describes that unless there is an update to an existing item that nothing will be returned.

Related

dynamodb.getItem returns {} when searching for a record that ends with ID

I've hit a weird problem where dynamodb.getItem returns {} when I specify a parameter that ends with ID:
var AWS = require("aws-sdk");
AWS.config.update({ region: "ap-southeast-2" });
var dynamodb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
const tableName = "ReportingDB"
async function logReports() {
try {
var params = {
Key: {
"Category": { "S": "Certification" },
"Report": { "S": "By EmployeeID" }
},
TableName: tableName
};
var result = await dynamodb.getItem(params).promise()
console.log(JSON.stringify(result))
} catch (error) {
console.error(error);
}
}
When I change the value "By EmployeeID" to "By Employee Number" it then works, why?
async function logReports() {
try {
var params = {
Key: {
"Category": { "S": "Certification" },
"Report": { "S": "By Employee Number" }
},
TableName: tableName
};
var result = await dynamodb.getItem(params).promise()
console.log(JSON.stringify(result))
} catch (error) {
console.error(error);
}
}
To reproduce, create a DynamoDB table with two columns Category and Report, then add an item with "Certification" and "By EmployeeID/Number" values respectively.
The error handling in DynamoDB is pretty good, typically it will fail with an error message such as Reserved keyword (eg Using a ProjectionExpression with reserved words with Boto3 in DynamoDB) however with "By EmployeeID" it doesn't produce any error, it just doesn't return anything. Could it be a bug or something I don't know about? I couldn't find it documented.
PS I've inserted the values in the dynamo db using the web console.
The documentation for GetItem explains that:
If there is no matching item, GetItem does not return any data and there will be no Item element in the response.
In other words, if there is no item matching the given key, you'll get an empty result - not an error message. I suspect that this is exactly what is happening in your case.
I don't know why it didn't find an item with "By EmployeeID". I don't think it's a bug involving the letters "ID" :-) I suspect that you simply have a bug in the code which inserted this item, perhaps mis-spelling the word "By EmployeeID". Please look again at the code which inserts this item, or use the AWS DynamoDB UI (or do a Scan request) to inspect the contents of your table manually to see what it actually contains.

Error while inserting Item into DynamoBD with SQS-Lambda integration

I have created a Lambda function which puts an Item in the DynamoDB table using Node.js 10.x. The Lambda function has been integrated with SQS Queue via trigger. When I put a message in the Queue the Lambda is invoked, but is throwing an error while inserting an Item in the DynamoDB table.
Message -> SQS -> Lambda -> DynamoDB
I am passing the TableName and the Item as the input to the DynamoDB put method. But, the CloudWatch Logs says that TableName and Item parameters are missing. Below are the code snippets and the screenshots.
I did spend a good amount of time, but not able to get around the problem. Could someone help me?
Lambda Code
console.log('Loading function');
var AWS = require('aws-sdk');
var dynamo = new AWS.DynamoDB.DocumentClient();
exports.handler = function(event, context, callback) {
console.log('Received event:', JSON.stringify(event, null, 2));
event.Records.forEach(record => {
const { body } = record;
console.log("Input to DynamoAPI :", body);
dynamo.put(body, callback);
});
return {};
}
Message that goes into the Queue
{
"TableName": "user-transaction",
"Item" : {
"transaction-id": 1
}
}
Error message from the CloudWatch
I did not try this out, but it looks to me like there is a missing JSON.parse() around the body variable in the dynamo put invocation.
From what I remember, SQS stringifies the body and it is not parsed automatically.
The following answer which I found on SO sums this up perfectly: [1].
References
[1] https://stackoverflow.com/a/56925968/10473469
I checked a similar lambda of my own thats successfully doing a put.
var params = {
TableName: dynamoUserTableName,
Item:{
"userId" : { S: event.request.userAttributes.sub},
"email" : { S: event.request.userAttributes.email},
"userName" : { S: event.userName},
"createdDate" : { S: createdDate },
"version" : { N: '1'}
}
};
console.log(params);
dynamodb.putItem(params, function(err, data) {...
Here is the output from my console just before the put
{ TableName: 'Users',
Item:
{ userId: { S: 'xxxxxxxxxxxxxxxxxxxxxxxxx' },
email: { S: 'test#example.co.uk' },
userName: { S: 'xxxxxxxxxxxxxxxxxxxxxxxx' },
createdDate: { S: '2020-05-02T07:49:23.478' },
version: { N: '1' } } }
I note there are no quotes around my attribute names, maybe this is an issue?

Remove JSON Element if it doesn't contain a specific value

I'm trying to return only values where john is found from a DynamoDB database.
I'm able to return values where it contains name: john from a mapped list, however the problem am having is that it appears to also be returning other values as well.
Running select: 'count' returns 1 match which is correct but it doesn't return anything when used.
I'm assuming that count just returns a number and not a specific select where john is matched.
I'm writing this in NodeJS; am hoping someone can help me figure this out.
I know that the value I only want shown are json elements where name: john, anything else I want omitted from being shown.
Here's my result as of right now:
{
"Department": [
{
"employees": [
{
"name": "john"
},
{
"name": "sally"
}
]
}
],
"Count": 1
}
My code:
const AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies
const dc = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event, context, callback) => {
// Construct the params for filtering data through dynamodb
const params = {
FilterExpression: "contains(#department, :employees)",
ExpressionAttributeNames: {
"#department": "employees",
},
ExpressionAttributeValues: {
":employees": {
"name":"john"
}
},
ProjectionExpression: "#department",
TableName: 'mytable',
//Select: 'COUNT'
};
const resultDC = await dc.scan(params).promise();
var items = resultDC.Items;
var count = resultDC.Count;
var returned_list = {
'Department' : items,
'Count' : count,
};
// create a response
const response = {
statusCode: 200,
body: JSON.stringify(returned_list),
};
callback(null, response);
};
I suggest you to use a Local Secondary Index.
Take a look here.

AWS Lambda function to Retrieve a DynamoDB column by passing primary key as a parameter

I am trying to retrieve values from DynamoDB when passing the primary partition key as the parameters in the URL.
I have a table with two columns:
movie id
movie name.
I want to be able to pass the movie id in the URL and to get the correspondent movie as a result. I have already created following lambda function and connected it to an API and DynamoDB.
I am not able to figure out the piece of code to use in order to retrieve the movie name when passing movie id as a parameter
Here is my code so far:
console.log('Loading function');
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region: 'us-east-2'});
exports.handler = function(event, context,callback) {
var params = {
TableName: 'movie',
Key: {
"movieID": 5,
}
}
docClient.get(params, function(err, data){
if(err){
callback(err,null);
}else{
callback(null, data);
}
})
};
Try
var params = {
TableName: 'movie',
Key: {
"movieID": 5,
},
AttributesToGet= [
"movie_name"
],
ProjectionExpression: 'movie_name"
}
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html
AttributesToGet is a legacy field as per documentation and ProjectionExpression should be used instead.

GET data from DynamoDB using Node JS SDK

I am quite new to work with DynamoDB. I would like to query DynamoDB database for a specific column value and get the data that matches that specific column value using NodeJS sdk
In this case, the DynamoDB is already deployed.
Please suggest how to implement this workflow using Node JS.
most important thing is to create a JSON object containing
the parameters needed to query the table, which in this example includes the table name, the
ExpressionAttributeValues needed by the query, a KeyConditionExpression that uses those
values to define which items the query returns, and the names of attribute values to return for each
item. Call the query method of the DynamoDB service object.
here is an example to query dynamodb with nodejs sdk
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set the region
AWS.config.update({region: 'REGION'});
// Create DynamoDB service object
var b = new AWS.DynamoDB({apiVersion: '2012-08-10'});
var params = {
ExpressionAttributeValues: {
':s': {N: '2'},
':e' : {N: '09'},
':topic' : {S: 'PHRASE'}
},
KeyConditionExpression: 'Season = :s and Episode > :e',
ProjectionExpression: 'Episode, Title, Subtitle',
FilterExpression: 'contains (Subtitle, :topic)',
TableName: 'EPISODES_TABLE'
};
b.query(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
data.Items.forEach(function(element, index, array) {
console.log(element.Title.S + " (" + element.Subtitle.S + ")");
});
}
});

Resources