Scanning DynamoDB table not showing results from the column specified in ProjectionExpression - node.js

i'm trying to scan the DynamoDB tale so that i fetch only filtered items.
myTable has 3 columns:L timestamp (String, PK), colors (String), userId (String)
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
"TableName": "myTable",
"ProjectionExpression": "colors, userId",
"ExpressionAttributeValues": {":val": userId},
"FilterExpression": "userId = :val"
};
console.log("Scanning table.");
docClient.scan((params), function(err,data){
if (err) console.log(err, err.stack);
else console.log(data); //success response
});
2018-05-22T08:04:21.395Z baac6d92-5d96-11e8-ae78-bd04c275acf5 Scanning table.
2018-05-22T08:04:21.672Z baac6d92-5d96-11e8-ae78-bd04c275acf5 { Items: [ { userId: 'amzn1.ask.account.XYZ' } ], Count: 1, ScannedCount: 2 }
As a result i'm only getting value(s) from userId column. The column 'colors' is completely ignored.
What am i doing wrong?

Setting ProjectionExpression attributes in ExpressionAttributeNames. Check out the following snippet
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
ExpressionAttributeNames: {
"#colors": "colors",
"#userId": "userId"
},
ExpressionAttributeValues: {
":val": userId
},
FilterExpression: "userId = :val",
ProjectionExpression: "#colors, #userId",
TableName: "myTable"
};
console.log("Scanning table.");
docClient.scan(params, function(err, data) {
if (err) console.log(err, err.stack);
else console.log(data); //success response
});
Note the # and : must be present on ExpressionAttributeNames and ExpressionAttributeValues, respectively.

Related

unable to get all items using query DynamoDB

How to scan all items from AWS dynamodb using node.js. I am posting my code here.
//Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
var unmarshalItem = require('dynamodb-marshaler').unmarshalItem;
// Set the region
AWS.config.update({region: 'us-east-1'});
// Create DynamoDB service object
var b = new AWS.DynamoDB({apiVersion: '2012-08-10'});
exports.handler = (event, context, callback) => {
var params = {
TableName: 'IoTdata2',
FilterExpression: "#deviceid = :unitID and #devicetimestamp BETWEEN :ftimestamp and :ttimestamp",
ExpressionAttributeNames: {
"#deviceid": "id",
"#devicetimestamp": "timestamp"
},
ExpressionAttributeValues: {
':unitID': {S: 'arena-MXHGMYzBBP5F6jztnLUdCL' },
':ftimestamp' : {S: '1584022680000' },
':ttimestamp' : {S: '1584023280000' }
},
};
b.scan(params, onScan);
function onScan(err, data) {
if (err) {
console.error("Unable to scan the table. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Scan succeeded.");
var items = data.Items.map(function(val){
return unmarshalItem(val);
})
// continue scanning if we have more items
if (typeof data.LastEvaluatedKey != "undefined") {
console.log("Scanning for more...");
params.ExclusiveStartKey = data.LastEvaluatedKey;
b.scan(params, onScan);
}
}
callback(null, items);
}
};
I have followed the link https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.04.html
I am getting time out here after a while. I have checked this link too
How to fetch/scan all items from `AWS dynamodb` using node.js
I am unable to return data properly i guess, Any suggestions ? Thanks
This worked for me by following Hank solution from here: How to fetch/scan all items from `AWS dynamodb` using node.js
exports.handler = async (event, context, callback) => {
let params = {
ExpressionAttributeNames: {
"#deviceid": "id",
"#devicetimestamp": "timestamp"
},
ExpressionAttributeValues: {
':unitID': {S: event.deviceid },
':ftimestamp' : {S: event.fromtime },
':ttimestamp' : {S: event.totime }
},
KeyConditionExpression: '#deviceid = :unitID and #devicetimestamp BETWEEN :ftimestamp and :ttimestamp',
TableName: 'IoTdata2'
};
let scanResults = [];
let items;
do {
items = await b.query(params).promise();
items.Items.map((item) => scanResults.push(unmarshalItem(item)));
params.ExclusiveStartKey = items.LastEvaluatedKey;
} while (typeof items.LastEvaluatedKey != "undefined");
var len = scanResults.length;
console.log(len);
callback(null, scanResults);
};

How to sort data from dynamo DB using nodeJS in AWS-lambda

I am retrieving data from the table using onScan in lambda function. I want to sort them based on the timestamp. Please advise on this
var params = {
TableName: "LogEvents",
FilterExpression: "#Environment = :env",
ExpressionAttributeNames: {
"#Environment": "Environment",
}
};
Hope following example will help you.
var params = {
TableName: "Table",
IndexName: "DataID-Created-index",
KeyConditionExpression: "DataID = :v_ID AND
Created > :v_created",
ExpressionAttributeValues: {":v_ID": {S: "some_id"},
":v_created": {N: "timestamp"}
},
ProjectionExpression: "ID, DataID, Created, Data"
};
ddb.query(params, function(err, data) {
if (err)
console.log(err);
else {
data.Items.sort(function(a, b) {
return parseFloat(a.Created.N) -
parseFloat(b.Created.N);
});
// More code here
}
});

How to scan in dynamoDB based on the values in an array?

here is my code where i have a list of values in an array. I need to fetch all the projects from project table which matches the id's in the array.
var arr=[];
for(var index in data.Items){
if(data.Items[index].hasOwnProperty('projectId'))
arr.push(data.Items[index].projectId);
};
var params = {
TableName: 'projects',
FilterExpression: 'id IN (:id)',
ExpressionAttributeValues: {
':id': arr
}
};
dynamodbclient.scan(params, function (err, docs) {
if (err) {
console.log("Error", err);
} else {
console.log("Success");
callback(err, docs.Items);
}
});
However i am not getting the proper results.
Option 1 - Static :-
If you know all the values its count upfront, please construct the FilterExpression as mentioned below:-
var params = {
TableName : "projects",
FilterExpression : "id IN (:id1, :id2)",
ExpressionAttributeValues : {
":id1" : "id val 1",
":id2" : "id val 2"
}
};
Option 2 - Dynamic:-
var titleValues = ["The Big New Movie 2012", "The Big New Movie"];
var titleObject = {};
var index = 0;
titleValues.forEach(function(value) {
index++;
var titleKey = ":titlevalue"+index;
titleObject[titleKey.toString()] = value;
});
var params = {
TableName : "Movies",
FilterExpression : "title IN ("+Object.keys(titleObject).toString()+ ")",
ExpressionAttributeValues : titleObject
};
docClient.scan(params, onScan);
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 :", 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);
}
}
}

Getting null value when trying to query value which is not present in dynamo db using node.js

I am new to dynamoDB and node.js I have written a code where it will make a query to the database (dynamodb) and look for an element which is entered by the user in the database. I am able to verify that but when the user tries with some other number which is not present in the database I am getting a null value.
My table name is "DevReferenceNumber" and only one column which is primary key "referencenumber".
'use strict';
var AWS = require('aws-sdk');
var docClient = new AWS.DynamoDB.DocumentClient({ region : 'us-east-1'});
function close(sessionAttributes, fulfillmentState, message) {
return {
sessionAttributes,
dialogAction: {
type: 'Close',
fulfillmentState,
message,
},
};
}
exports.handler = (event, context, callback) => {
try{
console.log(`event.bot.name=${event.bot.name}`);
if(event.bot.name != 'getCustomerReferenceNumber'){
callback('Invalid Bot Name');
}
dispatch(event, (response) => {
callback(null, response)
});
}catch(err){
callback("Error is occured while querying");
}
};
function dispatch(intentRequest, callback){
console.log(`dispatch UserID => ${intentRequest.userId}, intentName => ${intentRequest.currentIntent.name}`);
const intentName = intentRequest.currentIntent.name;
if(intentName === "checkReferenceNumber"){
return referenceNumber(intentRequest, callback);
}
}
function referenceNumber(intentRequest, callback){
const enteredReferenceNumber = intentRequest.currentIntent.slots.ReferenceNumber;
const sessionAttributes = intentRequest.sessionAttributes;
console.log("User has entered reference number is --> " + enteredReferenceNumber);
var params = {
TableName : "DevReferenceNumber",
KeyConditionExpression: "#refer = :ref",
ProjectionExpression : "#refer",
ExpressionAttributeNames: {
"#refer" : "referencenumber"
},
ExpressionAttributeValues:{
":ref": parseInt(enteredReferenceNumber)
}
};
docClient.query(params, function(err, data){
if(err){
callback(close(sessionAttributes, 'Fulfilled', {
contentType: 'PlainText',
content : 'Developer reference number is not matched with data from database'}));
}
else {
data.Items.forEach(function (item){
console.log("User matched data is ==> " + item.referencenumber);
callback(close(sessionAttributes, 'Fulfilled', {
contentType: 'PlainText',
content : 'Developer reference number is matched with data from database'}));
});
}
});
}
It is obvious that you will get a null record when you don't have a matching record. If you don't want null from node callback then you can do a custom logic to do a null check and return data according to the way you want.

How to update() DynamoDB

I'm working with DynamoDB for the first time and so far, not too bad. Having some understanding of Node is making this easier, but having none of noSQL, well that hurts!. My application relies on quickly searching a GROUPS list and returning members from that group.
When I add the data using the console, I am able to create a JSON document like this:
"GROUP_ID":"GroupA", "MEMBER": ["MemberA", "MemberB", "MemberC"], "STATUS": ["OWNER", "MEMBER", "INVITED"], "ADD_DATE":[1234567, 2345671, 3456712]
I am using this to create the GROUP_ID as the primary key:
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region:'us-east-1'});
exports.handler = (event, context, callback) => {
var tableName = "USER_GROUPS";
var checkParams = {
TableName: tableName,
Key:{"GROUP_NAME": event.group_id}
};
var createParams = {
TableName: tableName,
Key:{"GROUP_NAME": event.group_id},
Item:{"GROUP_NAME": event.group_id, "MEMBER_NAME":[event.device_id], "MEMBER_SATUS":["OWNER"], "MEMBER_DATE" : [event.date]}
};
var checkGroupExists = new Promise((resolve, reject) => {
docClient.get(checkParams, (err, data) => {
if(err){
reject(err);
}
if(data.Item){ // exists...
console.log("found Group ID");
reject();
}
else{
console.log("Group ID not found...");
resolve();
}
});
});
checkGroupExists.then((err, data) => {
console.log("adding Group: ");
console.log(data);
docClient.put(createParams, (err, data) =>{
if(err){
console.log(err);
callback(err, null);
}else{
console.log("added device: " + createParams.Key);
callback(null, {"created":createParams.Key.GROUP_NAME});
}
});
}).catch((err) => {
if(err){
callback(err, null);
}
else{
callback(err, {"used":createParams.Key.GROUP_NAME});
}
});
};
but when I use update() I am adding to the array and end up with a type name for the arrays
["S":"MemberA", "S":"MemberB", "S":"MemberC"]
kind of thing....
This is where I have left off, quite frustrated here!
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region:'us-east-1'});
exports.handler = (event, context, callback) => {
var tableName = "USER_GROUPS";
var checkParams = {
TableName: tableName,
Key:{"GROUP_NAME": event.group_id},
Item:{"MEMBER_NAME": event.member_name}
};
var updateParams = {
TableName: tableName,
Key:{"GROUP_NAME": event.group_id},
//Item:{"MEMBER_NAME":[event.device_id], "MEMBER_STATUS":["OWNER"], "MEMBER_DATE" : [event.date]},
AttributeUpdates: {
"MEMBER_NAME": {
Action: 'ADD',
Value: event.device_id
},
"MEMBER_STATUS":{
Action : 'ADD',
Value: "ENVITED"
},
"MEMBER_DATE":{
Action: 'ADD',
Value: event.date
}
},
};
var checkGroupExists = new Promise((resolve, reject) => {
docClient.get(checkParams, (err, data) => {
console.log(data);
if(err){
reject(err);
}
if(data.Item.GROUP_NAME){ // exists...
console.log("found the group...");
resolve();
}
else{
reject();
}
});
});
checkGroupExists.then((err, data) => {
docClient.update(updateParams, (err, data) =>{
if(err){
console.log(err);
callback(err, null);
}else{
callback(null, {"updated" : updateParams.Key.GROUP_NAME});
}
});
}).catch((err) => {
if(err){
callback(err, null);
}
else{
callback(err, {"noGroup":createParams.Key.GROUP_NAME});
}
});
};
It seems I am lacking the understanding of how to process updates to include NEW item in the member array. Any assistance would be appreciated!
Use list_append() together in an UpdateExpression to append to a list column along with a ConditionExpression to prevent updates to a non-existent group:
const AWS = require('aws-sdk');
const DB = new AWS.DynamoDB.DocumentClient({region:'us-east-1'});
const UpdateExpression = 'SET ' + [
'#members = list_append(#members, :member)',
'#statuses = list_append(#statuses, :status)',
'#dates = list_append(#dates, :date)',
].join(', ')
const ConditionExpression = [
'attribute_type(#members, :L)',
'attribute_type(#statuses, :L)',
'attribute_type(#dates, :L)'
].join(' AND ')
const ExpressionAttributeNames = {
'#members': 'MEMBER_NAME',
'#statuses': 'MEMBER_STATUS',
'#dates': 'MEMBER_DATE'
}
exports.handler = (event, context, callback) => {
DB.update({
TableName: 'USER_GROUPS',
Key: { GROUP_NAME: e.group_id },
ReturnValues: 'ALL_NEW',
UpdateExpression: UpdateExpression,
ConditionExpression: ConditionExpression,
ExpressionAttributeNames: ExpressionAttributeNames,
ExpressionAttributeValues: {
':member': [e.member_name],
':status': ['ENVITED'],
':date': [e.date],
':L': 'L'
}
}, callback)
}

Resources