Update dynamoDB column using condition expression - amazon-web-services

I want to update existing item of dynamoDB table using condition equivalent to like (%) condition of sql
opIdUserId status
123-U1 inprogress
345-U2 inprogress
123-U3 onhold
opIdUserId in my dynamodb is Primary partition key. I want to update status to COMP for opIdUserId field value starting from or contains 123.
this is what I am trying currently but researched and found I can not use KeyConditionExpression for update.
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region: 'eu-west-1'});
var table = "tablename";
exports.handler = function(event, context, callback){
var params = {
TableName: table,
KeyConditionExpression: "begins_with(opIdUserId, :i)",
UpdateExpression: "set operationStatus = :o",
ExpressionAttributeValues:{
":o":"COMP",
":i":"123-"
},
ReturnValues:"UPDATED_NEW"
};
docClient.update(params, function(err, data) {
if (err) {
callback(err, null);
} else {
callback(null,data);
}
});
}
Please suggest how I can update my item in dynamoDB with specific condition.

You should create a Global Secondary Index on your table to query for the items that start with 123 using a KeyConditionExpression.
var params = {
TableName: table,
KeyConditionExpression: "id = :id AND begins_with(opIdUserId, :opIdUserId)",
UpdateExpression: "set operationStatus = :operationStatus",
ExpressionAttributeValues:{
":opIdUserId":"123-",
":id": "something"
}
};
var documentClient = new AWS.DynamoDB.DocumentClient();
documentClient.query(params, function(err, data) {
if (err) console.log(err);
else console.log(data);
});
Bare in mind that you can't run a query using BEGINS_WITH on a partition key, only on a sort key.
Then, you can use the update method over every individual element using the partition and sort key for the table, updating the operationStatus.
If you provide me with information regarding your DynamoDB table, I could help you create the GSI.

Related

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.

aws dynamodb - how to query by date for sort key

I want to query the table and get data which is after certain date.
Hash Key: id
Sort Key: timestamp
error
ValidationException: Query condition missed key schema element: id
index.js
var aws = require('aws-sdk');
const dynamodb = new aws.DynamoDB();
exports.handler = async (event, context, callback) => {
const documentClient = new aws.DynamoDB.DocumentClient();
const params = {
TableName : 'dynamodb-log-testing',
KeyConditionExpression: '#myTimestamp >= :myDate',
ExpressionAttributeNames: {
"#myTimestamp": "timestamp"
},
ExpressionAttributeValues: {
':myDate': '2017-11-17'
}
};
try{
const data = await documentClient.query(params).promise();
console.log(data)
}catch(err){
console.log(err)
}
};
All queries on a DynamoDB table must include the partition key (aka HASH). You can use scan, but it's not recommended for most use cases. You can create a GSI where the partition on the index is a fixed value, and have the same timestamp value for the sort key. That will allow you to query the index in the way you are describing (except that you'll include the fixed value in the query as well). Your query would look like this:
var aws = require('aws-sdk');
const dynamodb = new aws.DynamoDB();
exports.handler = async (event, context, callback) => {
const documentClient = new aws.DynamoDB.DocumentClient();
const params = {
TableName : 'dynamodb-log-testing',
IndexName: 'myGSI1',
KeyConditionExpression: 'gsi1pk = :fixedValue and #myTimestamp >= :myDate',
ExpressionAttributeNames: {
"#myTimestamp": "timestamp"
},
ExpressionAttributeValues: {
':myDate': '2017-11-17',
':fixedValue': 'some fixed value'
}
};
try{
const data = await documentClient.query(params).promise();
console.log(data)
}catch(err){
console.log(err)
}
};
Keep in mind that this model has a strong potential for hot partitions on the GSI if your data is large. For that reason you may want to rethink the access pattern a bit. If you can do something like maybe include the date part of the timestamp in the partition and just include the time in the sort that would help. That does mean that you can't query across days in a single query.
Best Practices for Designing and Architecting with DynamoDB
has a lot of good information on best practices for DynamoDB.

AWS DynamoDB DocumentClient not throwing expected error

I'm using DynamoDB to store data and trying to read items using JavaScript. I have a function that will read an item from a specified table, but I want to detect when an item doesn't exist in the table:
function getChapterLocations() {
var table = bibleSelect.value.replace(/\s/g, '');
var chapter = bookSelect.value + " " + chapterSelect.value;
var params = {
TableName: table,
Key:{
"chapter": chapter
}
};
var docClient = new AWS.DynamoDB.DocumentClient();
docClient.get(params, function(err, data) {
if (err) {
currentLocations = {};
} else {
currentLocations = data.Item.locations;
}
getText();
});
}
The problem is, even when an item doesn't exist in the table, err is always null. When an item doesn't exist, all I get is an error that looks something like this in the console:
callListeners https://sdk.amazonaws.com/js/aws-sdk-2.164.0.min.js:48:1027
emit https://sdk.amazonaws.com/js/aws-sdk-2.164.0.min.js:48:695 emitEvent
https://sdk.amazonaws.com/js/aws-sdk-2.164.0.min.js:47:18756
I would just ignore this error, but when an item doesn't exist, it prevents getText() from being called.

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();
}
});

Adding a where clause to AWS DynamoDB

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}
}