Adding a where clause to AWS DynamoDB - amazon-web-services

I am trying to create a getItem request in AWS Lambda to access DynamoDB like so:
dynamodb.getItem({
TableName: "DataTable",
Key: {
user: {
S: user
},
deleted: {
BOOL: false
}
}
}, function(err, data) {
if (err) return fn(err);
else {
if ('Item' in data) {
fn(null, user);
} else {
fn(null, null); // User not found
}
}
});
It worked fine when I passed the user in as that was the primary key on the table. I added a deleted boolean to create a soft delete on users. But one I added that in the schema errors started to happen as deleted isn't part of the primary key. I want a way to add it as a where clause coming from the relational DB world. How is this done? Thanks. :o)

The getItem cannot be used if the data has to be filtered by any non-key attributes.
I think in the above case, the 'deleted'attribute is a non-key attribute. So, the Query API should be used to filter the data along with key attribute.
Please refer the FilterExpression in the below example.
FilterExpression : 'deleted = :createdate'
(AWS.Request) query(params = {}, callback)
Sample code:-
var params = {
TableName : table,
KeyConditionExpression : 'yearkey = :hkey and title = :rkey',
FilterExpression : 'deleted = :deleted',
ExpressionAttributeValues : {
':hkey' : year_val,
':rkey' : title,
':deleted' : {BOOL : false}
}
};
docClient.query(params, function(err, data) {
if (err) {
console.error("Unable to read item. Error JSON:", JSON.stringify(err,
null, 2));
} else {
console.log("GetItem succeeded:", JSON.stringify(data, null, 2));
}
});
For your use case, the key, filter condition and expression attribute value should be as mentioned below:-
KeyConditionExpression : 'user = :user',
FilterExpression : 'deleted = :deleted',
ExpressionAttributeValues : {
':user' : 'John',
':deleted' : {BOOL : false}
}

Related

Function scan in DynamoDB doesn't bring some of the results

I got a function in AWS Lambda that lists every patient in a table from DynamoDB. I realized that some items from the table were not on the list. This is my function to list:
module.exports.listPatients = async (event) => {
try {
const queryString = {
limit: 5,
...event.queryStringParameters,
};
const { limit, next, name } = queryString;
const localParams = {
...patientsParams,
Limit: limit,
FilterExpression: "contains(full_name, :full_name)",
ExpressionAttributeValues: { ":full_name": name },
};
if (next) {
localParams.ExclusiveStartKey = {
id: next,
};
}
const data = await dynamoDb.scan(localParams).promise();
const nextToken = data.LastEvaluatedKey ? data.LastEvaluatedKey.id : "";
const result = {
items: data.Items,
next_token: nextToken,
};
return {
statusCode: 200,
body: JSON.stringify(result),
};
} catch (error) {
console.log("Error: ", error);
return {
statusCode: error.statusCode ? error.statusCode : 500,
body: JSON.stringify({
error: error.name ? error.name : "Exception",
message: error.message ? error.message : "Unknown error",
}),
};
}
};
Am I missing something?
I tried with and without a limit, removed the filters, and yet nothing.
I tested one of the ids with get() to test with the server can find one of those who are missing, and it worked.
I am using Serverless to deploy the code, and when I try offline, it's working.
Stackoverflow recommended this post when writing my question, but I am using DynamoDB.DocumentClient without specifying the full attribute type in the filter expression:
How to scan in DynamoDB without primary sort key with Nodejs
Looks like you are paginating using scan(). Using query() with some Global Secondary Indexes and ScanIndexForward would give you a much better performance. scan() doesn't scale well when your data grows.

DynamoDB - The provided key element does not match the schema

I am trying to delete a user's reservation at a specific date and time but I encountered this error and am not sure how to resolve it. Any advice will be appreciated.
const AWS = require("aws-sdk");
const dynamo = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
let body;
let response;
switch (event.routeKey) {
case 'DELETE /bookings/{user_name}/{restaurant_name}/{time}/{date}':
//have to specify date and time because user might make reservation on same date,same restaurant, at 2 different timings
var params = {
TableName: 'hearty_eats_bookings',
Key: {
'user_name': event.pathParameters.user_name,
'restaurant_name': event.pathParameters.restaurant_name,
'time': event.pathParameters.time,
'date': event.pathParameters.date
},
};
dynamo.delete(params, function(err, result) {
if (err) throw err;
return callback(null, { "message": "booking cancelled" });
});
break;
default:
throw new Error("Unsupported route: " + event.routeKey);
}
}
Event JSON
Error Message
Event JSON
DynamoDB Details
DynamoDB's DeleteItem API only takes the keys of the item as a parameter, however you have included much more than the keys in your request:
Key: {
'user_name': event.pathParameters.user_name,
'restaurant_name': event.pathParameters.restaurant_name,
'time': event.pathParameters.time,
'date': event.pathParameters.date
},
If you need to manage an item at the time and data level, then you should include that as part of your key, for example:
PK
SK
Data
User123
GreatChinese#2022-12-10T18:00:000Z
Table for 2
User789
GreatIndian#2022-12-09T19:00:000Z
Table for 4
Key: {
'PK': event.pathParameters.user_name,
'SK': `${event.pathParameters.restaurant_name}#${event.pathParameters.date}`
},
If you wish to continue with your current approach then use the following as Key
Key: {
'user_name': event.pathParameters.user_name
},
In summary, you must only specify the tables partition key and sort key in the Keys parameter of the DeleteItem request.

lambda function returning null for deleting item in DynamoDB

hi Ive been trying to get my lambda function to delete an item in dynamo db but the function is simply returning null and i have no idea how to even start debugging it, hoping someone here has the knowledge to help
my table has guid as its primary partition key and username as its sort key
heres my code in .js
const AWS = require("aws-sdk");
// Initialising the DynamoDB SDK
const documentClient = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event) => {
const { guid, username } = event
const params = {
TableName: "Items", // The name of your DynamoDB table
Key:{
"guid": {"S" : guid},
"username": {"S" : username}
}
};
try {
// Utilising the scan method to get all items in the table
documentClient.delete(params, function(err, data) {
if (err) {
return("Unable to delete item. Error JSON:", JSON.stringify(err, null, 2));
} else {
return("DeleteItem succeeded:", JSON.stringify(data, null, 2));
}
});
}
catch (e) {
return {
statusCode: 500,
body: e
};
}
};
this is the payload for the test event im using in lambda
{
"guid": "34",
"username": "newusername"
}
You are using async function handler. So your function probably just finishes before your code actually has a chance to execute.
You can overcome this issue by wrapping your code around new Promise as shown in the docs

how to define attribute types in Dynamodb?

I want to store data attributes are threadId , threadType (sms, livechat ,fb) , createat and updateat how I define the threadType I follow this procedure but output displays all of the types of threadType?
and how to fix the time? this is manual input is there any method to get system time?
var doClient = new AWS.DynamoDB.DocumentClient();
var DynamoDB = new AWS.DynamoDB({});
var table = "thread";
var threadId = "3";
var threadType = "livechat";
var createDate = "11:38";
var updateDate = "12:00";
var channelName = "three";
var params = {
TableName : table,
Item:
{
"threadId" : threadId,
"threadType" : { "SS": ["sms", "livechat" ,"fb"] },
"createDate" : { 'S' : createDate },
"updateDate" : { 'S' : updateDate },
"channelName" :{'S' : channelName }
}
};
console.log("Adding a new item...");
doClient.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));
}
});
I need that only livechat display in a result of threadtype because in this insertion I need livechat
It looks like you are modelling threadType as a StringSet, which means that it can contain multiple values. If you just want to store 'livechat' then just store this value as a String. DynamoDB doesn't have the concept of server side validation, or support for Enums, though some SDK's do - in node.js there is no Enum type. As for the system time, there is no way to ask for DynamoDB to insert the system time for you. Most people will insert epoch seconds or milliseconds as a Number type for sorting purposes, and based on the client's timestamp, which should use NTP and when hosted within EC2 will be super super close to the DDB fleet timestamp.

DynamoDB delete table complete status

I am deleting a table in DynamoDB using the following Javascript in Node.
var params = {
TableName : "MyTable"
};
dynamodb.deleteTable(params, function(err, data) {
// Not really done yet...!
});
I need to know when the table has actually been deleted. The callback doesn't indicate this, as it is still in the deleting process when this is called. Is there a way to know when the delete has completed?
The waitFor API can be used to check for the non-existence of table.
Waits for the tableNotExists state by periodically calling the
underlying DynamoDB.describeTable() operation every 20 seconds (at
most 25 times).
Sample code to delete the table and check for the non-existence of table using waitFor API:-
var AWS = require("aws-sdk");
AWS.config.update({
region : "us-west-2",
endpoint : "http://localhost:8000"
});
var dynamodb = new AWS.DynamoDB();
var params = {
TableName : "country"
};
var paramsWaitFor = {
TableName : 'country' /* required */
};
function waitForTableNotExists() {
dynamodb.waitFor('tableNotExists', paramsWaitFor, function(waitForErr,
waitForData) {
if (waitForErr) {
console.log(waitForErr, waitForErr.stack); // an error occurred
} else {
console.log('Deleted ====>', JSON.stringify(waitForData, null, 2));
}
});
}
dynamodb.deleteTable(params, function(err, data) {
if (err) {
console.error("Unable to delete table. Error JSON:", JSON.stringify(
err, null, 2));
} else {
console.log("Deleted table. Table description JSON:", JSON.stringify(
data, null, 2));
waitForTableNotExists();
}
});