node.js: DynamoDB DocumentClient returning empty object - node.js

I am using DynamoDB local and can create and delete table. I created a table with only one key like below
const tablePromise = dynamodb.listTables({})
.promise()
.then((data) => {
const exists = data.TableNames
.filter(name => {
return name === tableNameLogin;
})
.length > 0;
if (exists) {
return Promise.resolve();
}
else {
const params = {
TableName: tableNameLogin,
KeySchema: [
{ AttributeName: "email", KeyType: "HASH"}, //Partition key
],
AttributeDefinitions: [
{ AttributeName: "email", AttributeType: "S" },
],
ProvisionedThroughput: {
ReadCapacityUnits: 10,
WriteCapacityUnits: 10
}
};
dynamodb.createTable(params, function(err, data){
if (err) {
console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
}
});
}
});
Now I want to insert an item in the table following example doc at AWS.
var docClient = new AWS.DynamoDB.DocumentClient();
var tableNameLogin = "Login"
var emailLogin = "abc#gmail.com";
var params = {
TableName:tableNameLogin,
Item:{
"email": emailLogin,
"info":{
"password": "08083928"
}
}
};
docClient.put(params, function(err, data) {
if (err) {
console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Added item:", JSON.stringify(data, null, 2));
}
});
When I run the insert item code, I get Added item: {} Why does it output an empty object? Is it actually inserting anything? I looked into this callback example but this time it doesn't output anything.

You need to add ReturnValues: 'ALL_OLD' to your put params. It will look like as mentioned below.
var params = {
TableName:tableNameLogin,
Item:{
"email": emailLogin,
"info":{
"password": "08083928"
}
},
ReturnValues: 'ALL_OLD'
};
For more details, you can follow this https://github.com/aws/aws-sdk-js/issues/803

Related

Problem with query on nested attribute DynamoDB

In my code I'm using the AWS.DynamoDB.DocumentClient() for interact with the DB.
My item structure is:
{
"docName": "drinkDoc",
"sortKey": "RISTRETTO",
"i18n": {
"de": "",
"en": "ristretto",
"fr": "",
"it": "ristretto"
},
"params": {
"size": [
"S",
"M",
"L",
"XL"
]
}
}
What I want to do is to retrieve the item filtering by i18n subproperties.
In my code I build a params object like this:
{
"TableName": "MyTable",
"KeyConditionExpression": "#docName = :docName",
"ExpressionAttributeNames": {
"#docName": "docName",
"#i18n": "i18n.it"
},
"ExpressionAttributeValues": {
":docName": "drinkDoc",
":drinkName": "ristretto"
},
"FilterExpression": "#i18n = :drinkName"
}
Then I execute the query in this way:
var docClient = new AWS.DynamoDB.DocumentClient();
docClient.query(params, (err, data) => {
if (err) {
console.error("Unable to retrieve data. Error JSON:", JSON.stringify(err, null, 2));
return reject(JSON.stringify(err, null, 2));
}
console.log("Read data succeeded:", JSON.stringify(data, null, 2));
resolve(data.Items);
});
So far so good.
The problem is that the query returns no item, but item exists in my database, as you can see:
What is wrong in this snippet?
I solved from my self.
As indicated in this link https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ExpressionAttributeNames.html
the code
{
"TableName": "MyTable",
"KeyConditionExpression": "#docName = :docName",
"ExpressionAttributeNames": {
"#docName": "docName",
"#i18n": "i18n.it"
},
"ExpressionAttributeValues": {
":docName": "drinkDoc",
":drinkName": "ristretto"
},
"FilterExpression": "#i18n = :drinkName"
}
must be replaced with
{
"TableName": "SmartCoffeeSkillTable",
"KeyConditionExpression": "#docName = :docName",
"ExpressionAttributeNames": {
"#docName": "docName",
"#i18n": "i18n",
"#locale": "it"
},
"ExpressionAttributeValues": {
":docName": "drinks",
":drinkName": "caffè"
},
"FilterExpression": "#i18n.#locale = :drinkName"
}
that is to replace
"FilterExpression": "#i18n = :drinkName" with "FilterExpression": "#i18n.#locale = :drinkName"

Update DynamoDB table with Node.JS returns reserved key word error

I am trying to update a DynamoDB table by following this AWS Tutorial, but I getting the following error:
Unable to update item. Error JSON: {
"message": "Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: hash",
"code": "ValidationException",
"time": "2021-11-10T07:54:18.832Z",
"requestId": "1e657754-c33d-4a55-8245-a107765e4261",
"statusCode": 400,
"retryable": false,
"retryDelay": 43.13890004813747
}
My code looks like this:
import AWS from 'aws-sdk';
var table = "Users";
export async function updateData(email, hash, callback){
AWS.config.update({
region: 'us-west-2',
endpoint: 'http://localhost:8000'
});
var docClient = new AWS.DynamoDB.DocumentClient()
var params = {
TableName: table,
Key:{
"email": email
},
UpdateExpression: "set hash = :var",
ExpressionAttributeValues:{
":var": hash
},
ReturnValues:"UPDATED_NEW"
};
docClient.update(params, function(err, data) {
if (err) {
console.error("Unable to update item. Error JSON:", JSON.stringify(err, null, 2));
callback(err, null);
} else {
callback(data, null);
}
});
}
updateData('joejava#icloud.com', 'hash', function(data, err){
console.log(err, data);
})
Any table has the following fields:
email (Key)
first_name
last_name
hash
As far as I can see, my code is very similar to the example.
What am I missing there?
hash is a dynamodb reserved keyword, so we must substitute it in as a ExpressionAttributeName.
var params = {
TableName: table,
Key:{
"email": email
},
UpdateExpression: "set #k = :var",
ExpressionAttributeNames:{
"#k": "hash"
},
ExpressionAttributeValues:{
":var": hash
},
ReturnValues:"UPDATED_NEW"
};

How to write data to local DynamoDB?

According to DynamoDB docs, you always need to specify --endpoint-url http://localhost:8000 option if you want to interact with your local (downloaded) version of DynamoDB. It works fine for me via aws cli, but, following their tutorial for Node.js developers, I've faced a strange issue: I have been interacting with data in DynamoDB web version instead of my local one, even if configured connection options to database:
const serviceConfigOptions: ServiceConfigurationOptions = {
region: "eu-north-1",
endpoint: "http://localhost:8000",
};
I described endpoint, but I have no results interacting with data in my local version and I have these in the web.
All code is here:
import fs from "fs";
import AWS, { AWSError } from "aws-sdk";
import { config as dotenvConfig } from "dotenv";
import {
CreateTableInput,
DocumentClient,
PutItemInput,
PutItemOutput,
} from "aws-sdk/clients/dynamodb";
import { ServiceConfigurationOptions } from "aws-sdk/lib/service";
dotenvConfig();
const serviceConfigOptions: ServiceConfigurationOptions = {
region: "eu-north-1",
endpoint: "http://localhost:8000",
};
const dynamoDB: AWS.DynamoDB = new AWS.DynamoDB();
const params: CreateTableInput = {
TableName: "Movies",
KeySchema: [
{
AttributeName: "year",
KeyType: "HASH",
},
{
AttributeName: "title",
KeyType: "RANGE",
},
],
AttributeDefinitions: [
{ AttributeName: "year", AttributeType: "N" },
{ AttributeName: "title", AttributeType: "S" },
],
ProvisionedThroughput: {
ReadCapacityUnits: 10,
WriteCapacityUnits: 10,
},
};
dynamoDB.createTable(params, (err, data): void => {
if (err) {
console.log("Unable to create table.");
console.error(err);
return;
}
console.log("Table created");
console.log(data);
});
const docClient: DocumentClient = new AWS.DynamoDB.DocumentClient();
console.log("Imporing data to DynamoDB");
fs.readFile(
"moviedata.json",
"utf-8",
(err: NodeJS.ErrnoException | null, data: string): void => {
if (err) {
console.log("Unable to read a file");
console.error(err);
return;
}
const allMovies: Array<any> = JSON.parse(data);
allMovies.forEach(({ year, title, info }): void => {
const params: PutItemInput = {
TableName: "Movies",
Item: {
year,
title,
info,
},
};
docClient.put(params, (err: AWSError, data: PutItemOutput) => {
if (err) {
console.error(
"Unable to add movie",
title,
". Error JSON:",
JSON.stringify(err, null, 2),
);
return;
}
console.log("PutItem succeeded:", title);
});
});
},
);
UPDATE:
Refactored code into promises.
import fs from "fs";
import { promisify } from "util";
import AWS, { AWSError } from "aws-sdk";
import { config as dotenvConfig } from "dotenv";
import {
CreateTableInput,
DocumentClient,
PutItemInput,
PutItemOutput,
} from "aws-sdk/clients/dynamodb";
import { ServiceConfigurationOptions } from "aws-sdk/lib/service";
dotenvConfig();
const serviceConfigOptions: ServiceConfigurationOptions = {
region: "eu-north-1",
endpoint: "http://localhost:8000",
};
const dynamoDB: AWS.DynamoDB = new AWS.DynamoDB();
const params: CreateTableInput = {
TableName: "Movies",
KeySchema: [
{
AttributeName: "year",
KeyType: "HASH",
},
{
AttributeName: "title",
KeyType: "RANGE",
},
],
AttributeDefinitions: [
{ AttributeName: "year", AttributeType: "N" },
{ AttributeName: "title", AttributeType: "S" },
],
ProvisionedThroughput: {
ReadCapacityUnits: 10,
WriteCapacityUnits: 10,
},
};
const createDBTable: (
params: AWS.DynamoDB.CreateTableInput,
) => Promise<AWS.DynamoDB.CreateTableOutput> = promisify(
dynamoDB.createTable,
).bind(dynamoDB);
const readFile = promisify(fs.readFile);
createDBTable(params)
.then(data => {
console.log("Table created");
console.log(data);
})
.catch(err => {
console.log("Unable to create table.");
throw new Error(err);
})
.then(() => {
console.log("Imporing data to DynamoDB");
return readFile("moviedata.json", "utf-8");
})
.then((data: string) => {
const allMovies: Array<any> = JSON.parse(data);
const docClient: DocumentClient = new AWS.DynamoDB.DocumentClient();
allMovies.forEach(({ year, title, info }): void => {
const params: PutItemInput = {
TableName: "Movies",
Item: {
year,
title,
info,
},
};
docClient.put(params, (err: AWSError, data: PutItemOutput) => {
if (err) {
console.error(
"Unable to add movie",
title,
". Error JSON:",
JSON.stringify(err, null, 2),
);
return;
}
console.log("PutItem succeeded:", title);
});
});
})
.catch(err => {
console.error(err);
});
Now I'm getting Unable to create table. Error: ResourceInUseException: Table already exists: Movies. However, in my local db only one Music table.
$ aws dynamodb list-tables --endpoint-url http://localhost:8000
Out:
{
"TableNames": [
"Music"
]
}
P.S. AWS_SDK_LOAD_CONFIG=1
I found the mistake I made.
I've configured params
const serviceConfigOptions: ServiceConfigurationOptions = {
region: "eu-north-1",
endpoint: "http://localhost:8000",
};
but I forgot to pass it to const dynamoDB: AWS.DynamoDB = new AWS.DynamoDB(); as an argument.
Must be
const serviceConfigOptions: ServiceConfigurationOptions = {
region: "eu-north-1",
endpoint: "http://localhost:8000",
};
const dynamoDB: AWS.DynamoDB = new AWS.DynamoDB(serviceConfigOptions);

Updating dynamoDB from Lambda function failed

I've got a problem updating DynamoDB entry.
The DB looks like this
{
"userId":"amzn1.ask.account.XYZ",
"mapAttr":{
"name":"John",
"colors":[
"yellow",
"white"
]
}
}
I want to update the List of colors utilizing follwoing code:
var docClient = new AWS.DynamoDB.DocumentClient({ apiVersion: "2012-08-10" });
var params = {
TableName: "myTable",
Key: {
userId: userId
},
UpdateExpression: "SET #mapAttr = list_append(#mapAttr, :entry)",
ExpressionAttributeNames: { "#mapAttr": "mapAttr.colors" },
ExpressionAttributeValues: {
":entry": ["blue"]
},
ReturnValues: "UPDATED_NEW"
};
docClient.update(params, function(err, data) {
if (err) {
console.error(
"Unable to update item. Error JSON:",
JSON.stringify(err, null, 2)
);
} else {
console.log("UpdateItem succeeded:", JSON.stringify(data, null, 2));
}
});
and i get the following message:
Unable to update item. Error JSON: { "message": "The provided key
element does not match the schema", "code": "ValidationException",
Any ideas why... ?
Per AWS documentation, you need to split your ExpressionAttributeNames up.
UpdateExpression: "SET #mapAttr.#colors = list_append(#mapAttr.#colors, :entry)",
ExpressionAttributeNames: {
"#mapAttr": "mapAttr",
"#colors": "colors"
}

Remove nested attribute in dynamodb

Let's say I have this item in DynamoDB:
{
"customerId": "customer_001",
"customerName": "itsme",
"address": {
"city": "Frankfurt",
"country": "Germany",
"street1": "c/o Company xxx",
"street2": "Europe",
"street3": "PO Box 406",
"zip": "12345"
}
}
I need to remove the nested attribute address.street3 from the item. How I can accomplish this?
Here is my code below; it works perfectly to remove non-nested attributes (for example, customerName), but if I try to use this in nested attributes (like address.street3), it silently fails.
const params = {
TableName: customerTable,
Key: {
customerId: customerId,
},
AttributeUpdates: {
'address.street3':
{
Action: 'DELETE'
}
}
};
dynamoDb.update(params, function (err, data) {
if (err) {
console.error("Unable to update customer. Error JSON:", JSON.stringify(err, null, 2));
}
else {
console.log("UpdateCustomer succeeded:", JSON.stringify(data.Attributes));
responseHelper.ResponseHelper.success(JSON.stringify(data.Attributes), 200, callback);
}
});
What can I remove the nested attribute address.street3?
Here is the code to remove "address.street3" attribute.
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
TableName : "customer",
Key : {
"customerId": "customer_001"
},
UpdateExpression : "REMOVE address.street3",
ReturnValues : "UPDATED_NEW"
};
console.log("Updating the item...");
docClient.update(params, function(err, data) {
if (err) {
console.error("Unable to update item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("UpdateItem succeeded:", JSON.stringify(data));
}
});

Resources