So I need a recursive function in node.js for replacing this function call:
docClient.scan(params, callback)
More info see http://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/GettingStarted.NodeJs.04.html
Here is the recursive code to execute the scan until LastEvaluatedKey is available.
var AWS = require("aws-sdk");
var creds = new AWS.Credentials('akid', 'secret', 'session');
AWS.config.update({
region: "us-west-2",
endpoint: "http://localhost:8000",
credentials : creds
});
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "Movies"
};
console.log("Scanning Movies table.");
docClient.scan(params, onScan);
var count = 0;
function onScan(err, data) {
if (err) {
console.error("Unable to scan the table. Error JSON:", JSON.stringify(err, null, 2));
} else {
// print all the movies
console.log("Scan succeeded.");
data.Items.forEach(function(movie) {
console.log("Item :", ++count,JSON.stringify(movie));
});
// continue scanning if we have more movies
if (typeof data.LastEvaluatedKey != "undefined") {
console.log("Scanning for more...");
params.ExclusiveStartKey = data.LastEvaluatedKey;
docClient.scan(params, onScan);
}
}
}
Recursive DynamoDB Scan using AWS SDK V3.
import {
DynamoDBClient,
ScanCommand,
ScanCommandOutput,
ScanCommandInput,
} from '#aws-sdk/client-dynamodb';
import { unmarshall, marshall } from '#aws-sdk/util-dynamodb';
const client = new DynamoDBClient({ region: 'eu-west-1' });
export const scanTable = async<ResultType>(params: ScanCommandInput): Promise<ResultType[]> => {
const scanParams: ScanCommandInput = params;
const results = [];
let lastEvaluatedKey: string;
do {
console.log(`Running query: ${JSON.stringify(scanParams)}`);
const { Items, LastEvaluatedKey } = await client.send(new ScanCommand(scanParams));
lastEvaluatedKey = LastEvaluatedKey;
Items.forEach((item) => results.push(unmarshall(item)));
scanParams.ExclusiveStartKey = LastEvaluatedKey;
} while (typeof lastEvaluatedKey !== 'undefined');
return results as ResultType[];
};
const items = await scanTable({ TableName: 'dynamo-table' })
Related
I have a Lambda with the following code:
// Load the AWS SDK for Node.js.
var AWS = require("aws-sdk");
// Set the AWS Region.
AWS.config.update({ region: "us-east-2" });
exports.handler = function(event, context, callback) {
// Create DynamoDB service object.
var ddb = new AWS.DynamoDB({ apiVersion: "2012-08-10" });
var params = {
TableName: "Ranking",
ProjectionExpression: "#username, Score, Duration",
FilterExpression: "#username = :username",
ExpressionAttributeNames: {
"#username": "Username",
},
ExpressionAttributeValues: {
":username": {
S: 'Alberto'
},
}
};
let toReturn = [];
ddb.scan(params, function (err, data) {
if (err) {
toReturn = err
} else {
toReturn = data.Items;
}
});
let response = {
statusCode: 200,
body: JSON.stringify(toReturn)
};
callback(null, response)
};
However I always see [] as response...
My current DB has the following records:
So my question is... why I don't get back that item?
Since you are using callbacks, your code should be as below. Also Duration is reserved keyword, so it also needs to be modified as below:
// Load the AWS SDK for Node.js.
var AWS = require("aws-sdk");
// Set the AWS Region.
AWS.config.update({ region: "us-east-2" });
exports.handler = function(event, context, callback) {
// Create DynamoDB service object.
var ddb = new AWS.DynamoDB({ apiVersion: "2012-08-10" });
var params = {
TableName: "Ranking",
FilterExpression: "#username = :username",
ProjectionExpression: "#username, Score, #duration",
ExpressionAttributeNames: {
"#username": "Username",
"#duration": "Duration",
},
ExpressionAttributeValues: {
":username": {
S: 'Alberto'
},
}
};
ddb.scan(params, function (err, data) {
if (err) {
callback(null, err)
} else {
callback(null, data.Items)
}
});
};
Consider the code :
const AWS = require('aws-sdk');
const dynamoDB = new AWS.DynamoDB({
region : 'us-east-2' ,
apiVersion: '2012-08-10'
});
exports.handler = async (event , context , callback) => {
const type = event.type;
if (type === 'all') {
// Which table we want to scan
const params = {
TableName : 'compare-yourself'
};
await dynamoDB.scan(params ,(err , data) => {
if (err) {
callback(err);
}
else{
callback(null , data);
}
});
// callback(null , "All Data");
}
else if (type === 'single') {
callback(null , "Single data");
}
else{
callback(null , "Everything else...");
}
};
When I test this piece of code on AWS Lambda with the value :
The result is always "Response: null" , even through there is data in the DynamoDB table compare-yourself.
What might be the problem here ?
Promise will solve the issue. I prefer documentclient.
const AWS = require('aws-sdk');
const documentClient = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event, context, callback) => {
const type = event.type;
if (type === 'all') {
const params = {
TableName: 'compare-yourself'
};
let data = await documentClient.scan(params).promise();
callback(null, data);
} else if (type === 'single') {
callback(null, "Single data");
} else {
callback(null, "Everything else...");
}
};
The data will be an object with table values in the Items,
{
Items: [],
Count:
ScannedCount:
.....
}
try use DocumentClient();
var documentClient = new AWS.DynamoDB.DocumentClient();
const params = {
TableName : 'compare-yourself'
};
documentClient.scan(params, function(err, data) {
if (err) console.log(err);
else console.log(data);
});
Mistake:
The problem is you are doing both callback and await at the same.
Fix:
So you could put the scan function in a try block, so on error
we do callback error in the catch block and stop the function without proceeding further (return) else you will send the data.
Code:
const AWS = require('aws-sdk');
const dynamoDB = new AWS.DynamoDB({
region : 'us-east-2' ,
apiVersion: '2012-08-10'
});
exports.handler = async (event , context , callback) => {
const type = event.type;
if (type === 'all') {
// Which table we want to scan
const params = {
TableName : 'compare-yourself'
};
try {
await dynamoDB.scan(params).promise();
} catch (e) {
callback(e);
return;
}
callback(null , data);
}
else if (type === 'single') {
callback(null , "Single data");
}
else{
callback(null , "Everything else...");
}
};
Note:
Just wanted to add this, when performing scan be aware of the limits, if the limit exceeds you won't get the entire entries in the table.
this is the node.js code:
'use strict';
const AWS = require("aws-sdk");
AWS.config.update({
region: 'eu-west-1'});
const docClient = new AWS.DynamoDB.DocumentClient();
const tableName = 'Fair';
const s3 = new AWS.S3();
exports.handler = async (event) => {
var getParams = {
Bucket: 'dataforfair', //s3 bucket name
Key: 'fairData.json' //s3 file location
}
const data = await s3.getObject(getParams).promise()
.then( (data) => {
//parse JSON
let fairInformations = JSON.parse(data.Body.toString());
fairInformations.forEach(function(fairInformationEntry) {
console.log(fairInformationEntry);
var params = {
TableName: tableName,
Item: {
"year": fairInformationEntry.year,
"fairName": fairInformationEntry.fairName,
"info": fairInformationEntry.info
}
};
docClient.put(params, function(err, data) {
console.log('*****test');
if (err) {
console.error("Unable to add fairInformation", fairInformationEntry.fairName, ". Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("PutItem succeeded:", fairInformationEntry.fairName);
}
});
});
})
.catch((err) => {
console.log(err);
});
const response = {
statusCode: 200,
body: JSON.stringify(data),
};
return response;
};
Hello everyone,
I want to put the data into the Dynamo DB after getting the JSON file from the s3 Bucket. Getting the JSON works and the console.log(fairInformationEntry); is also still triggered, but the docClient.put() never gets called. I am getting no error, nothing. I do not know what is wrong and why it is not working. I have the right IAM role and access to everything I need.
I hope you can help me!
The problem is mixup of promise, callback and async/await. You are also trying to do asynchronous operation inside foreach. The code should look something like this
"use strict";
const AWS = require("aws-sdk");
AWS.config.update({
region: "eu-west-1"
});
const docClient = new AWS.DynamoDB.DocumentClient();
const tableName = "Fair";
const s3 = new AWS.S3();
exports.handler = async event => {
var getParams = {
Bucket: "dataforfair", //s3 bucket name
Key: "fairData.json" //s3 file location
};
const data = await s3.getObject(getParams).promise();
//parse JSON
let fairInformations = JSON.parse(data.Body.toString());
await Promise.all(
fairInformations.map(fairInformationEntry => {
console.log(fairInformationEntry);
var params = {
TableName: tableName,
Item: {
year: fairInformationEntry.year,
fairName: fairInformationEntry.fairName,
info: fairInformationEntry.info
}
};
return docClient.put(params).promise();
})
);
const response = {
statusCode: 200,
body: JSON.stringify(data)
};
return response;
};
Hope this helps
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
Can someone give me a hand? I tried to figure it out but i ran out of ideas.
-------------dynamo.js....
module.exports.readUser = function (user_id) {
AWS.config = new AWS.Config();
AWS.config.update({region: "eu-west-1"});
var docClient = new AWS.DynamoDB.DocumentClient();
var table = "user";
var user_id = user_id;
var params = {
TableName: table,
Key:{
"user_id": user_id
}
};
docClient.get(params, function(err, data) {
if (err) {
return err;
} else {
//console.log(data); <-- data is filled
return data;
}
});
var dynamo = require("./dynamo.js");
console.log(dynamo.readUser(4711998));
The data you log out inside the function is only the returned value for the anonymous function given to docClient.get as the second argument. The exported readUser function has no return statement and therefore it is undefined.
Because of the async nature of javascript you have to access the result via a callback like so:
module.exports.readUser = function (user_id, cb) {
...
docClient.get(params, function(err, data) {
if (err) {
return err;
} else {
return cb(data);
}
});
}
var dynamo = require("./dynamo.js");
dynamo.readUser(4711998, function (user) {
console.log(user);
});
docClient.get is an asynchronous function. You need promisify this function or use callback.
Use callback:
module.exports.readUser = function (user_id, cb) {
AWS.config = new AWS.Config();
AWS.config.update({ region: "eu-west-1" });
var docClient = new AWS.DynamoDB.DocumentClient();
var table = "user";
var user_id = user_id;
var params = {
TableName: table,
Key: {
"user_id": user_id
}
};
docClient.get(params, cb);
}
var dynamo = require("./dynamo.js");
dynamo.readUser(4711998, function (err, user) {
if(err)
console.error(err);
else
console.log(user);
});
Use promise:
module.exports.readUser = function (user_id) {
AWS.config = new AWS.Config();
AWS.config.update({ region: "eu-west-1" });
var docClient = new AWS.DynamoDB.DocumentClient();
var table = "user";
var user_id = user_id;
var params = {
TableName: table,
Key: {
"user_id": user_id
}
};
return new Promise(function(resolve, reject) {
docClient.get(params, function(err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
var dynamo = require("./dynamo.js");
dynamo.readUser(4711998).then(function (user) {
console.log(user);
}).catch(function(err) {
console.error(err);
});
Read more:
How do I promisify the AWS JavaScript SDK?
https://aws.amazon.com/ru/blogs/developer/support-for-promises-in-the-sdk/
I have been trying to test this from lambda but unable to proceed.
var Alexa = require("alexa-sdk");
var dynamoDBConfiguration = {
"accessKeyId": "useraccess",
"secretAccessKey": "usersecretkey",
"region": "us-east-1"
};
var AWS = require("aws-sdk");
AWS.config.update(dynamoDBConfiguration);
var promisify = require("es6-promisify");
var dynClient = new AWS.DynamoDB.DocumentClient({"region":"us-east-
1"});
//convert callback style functions to promises
const dbGet = promisify(dynClient.get,dynClient);
const dbPut = promisify(dynClient.put,dynClient);
const dbDelete = promisify(dynClient.delete,dynClient);
var startStateHandlers = (GAME_STATES.STARt, {
"StartGame": function (isNewGame,context) {
const dynamoParams = {
TableName: "Userdata",
Key: {
"UserId":"test"
}
}
dbGet(dynamoParams)
.then(data => {
console.log('Get user succeeded', data);
const userId = data.UserId;
if (userId != null) {
console.log(data.UserName);
}
else {
// no match, add the user
return dbPut(dynamoParams);
}
})
.then(data => {
console.log('Add user succeeded', data);
})
.catch(err => {
console.error(err);
});
this.emit(":tell", speechOutput, speechOutput);
}
});
var handlers = {
"LaunchRequest": function () {
var speechOutput = "hello";
this.emit(":tell", speechOutput, speechOutput);
}
};
var handler = (function () {
function handler(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.appId = "appid";
alexa.registerHandlers(handlers, startStateHandlers);
alexa.execute();
}
return handler;
})();
exports.handler = handler;
It doesnt throw any error in the lamda logs and not able to see any log in Cloudwatch. It just executes the other lines of code.
I have attached all permission policy to the user and setup the lamda function as lambda_dynamo.
Unable to understand what is the issue with it.
Appreciate your help.
var dynamoDBConfiguration = {
"accessKeyId": "useraccess",
"secretAccessKey": "usersecretkey",
"region": "us-east-1"
};
var AWS = require("aws-sdk");
// update the AWS.Config global configuration object
AWS.config.update(dynamoDBConfiguration)
// Create DynamoDB document client
var dynClient = new AWS.DynamoDB.DocumentClient()