I have a Users table with an index on the username field. This makes it possible for me to search for users by username.
When I update an object's username field, fx from "Alice" to "Bob", then no items are returned to me when I subsequently call:
// Fetch the user with username Bob
const params = {
TableName: 'Users',
IndexName: 'username-index',
KeyConditionExpression: 'username = :value',
ExpressionAttributeValues: {
':value': 'Bob'
}
}
const result = await dynamo.query(params).promise()
It seems to me that "Bob" is not added to the index. I am doing the update in a wrong way or is there a way for me to update the index?
******************************* UPDATE *******************************
This is code used to update the username:
const params = {
TableName: 'Users',
Key: { _id: USER_ID },
UpdateExpression: 'SET username = :value',
ExpressionAttributeValues: {
':value': username
}
}
const result = await dynamo.update(params).promise()
I have looked in the AWS Console and verified that the username has in fact been changed. Also, when I look under Indexes I can see that the Item count for the username-index is 18, while the number of users is 19.
Related
I am working on one query where I need to use TrasactWrite of dynamoDB and perform update query on one of my table.
Scenario is I am having array of unique IDs and I need to perform same update operation on each ID in array and change one flag in table without using Loop or map.
But I am having difficulty in finding example or docs related to how do I use IN operator on IDs which are primary keys in a Key parameter of transactWrite.
Here is my sample code:
let IDs = await find('table', { type: 'some_type' }, 'type-index}
let params = {
TransactItems: [{
Update: {
TableName: 'table',
Key: '#_id IN :IDs,
UpdateExpression: 'set #flag = :flag',
ExpressionAttributeNames: {
'#flag': 'flag',
'#_id': '_id'
},
ExpressionAttributeValues: {
':flag': false,
":IDs": IDs
}
}
}]
}
Already tried: Answer Its not same question as mine
I will answer if anyone has any question. Any help will be really helpful. Thank you
You can't use IN operator in this case - Update. With update operator you have to put key value to Update object. A key includes partitionKey and sortKey, I think in your case, you just set partitionKey.
To update more than one item by ID, you can put many Update object to TransactItems.
let IDs = await find('table', { type: 'some_type' }, 'type-index');
let params = {
TransactItems: [], // init empty array
}
IDs.forEach((ID) => {// loop though IDs array
params.TransactItems.push({
Update: {
TableName: 'table',
Key: {
'_id': ID, // ID value
},
UpdateExpression: 'set #flag = :flag',
ExpressionAttributeNames: {
'#flag': 'flag',
// '#_id': '_id' // remove this line
},
ExpressionAttributeValues: {
':flag': false,
// ":IDs": IDs // remove this line
}
}
})
});
// await client.transactWrite(params).promise()
Here is an example. I am using AWS Lambda function in Node.JS. This is the object in DynamoDB:
{
email: "johndoe#gmail.com",
name: "John Doe",
score: "12"
}
Now I want to first check what his saved score is. If his current score is more than the score already present in DB then update the DB else leave it as it is. Currently, my code is updating it every time. I'm not sure how to proceed and which function to use.
If his score is 15, then after checking the DB it should update it to:
{
email: "johndoe#gmail.com",
name: "John Doe",
score: "15"
}
If his score is 7, it should leave it as it is.
{
email: "johndoe#gmail.com",
name: "John Doe",
score: "12"
}
Edit - The following issue has also been solved. Found a workaround. Still looking for answers. So leaving it open.
Now my issue is that I am using the same function for both updating and creating records. Is that possible?
If a new user plays the game his email, name, and score are saved to the DB. And if an existing user plays, only his score is updated if it is greater than the one in DB.
This is where I'm currently stuck. Getting these 2 issues,
1. name is a reserved keyword. I wonder how was it allowed me to use name as an attribute when i was just using put.
2. email cannot be updated since it is part of key.
Here is my current code,
function addToLeaderBoard(currentScore, email, name){
var params = {
TableName: tablename,
Key: {
"email": email
},
UpdateExpression: "set score = :num, name = :player, email = :mail",
ConditionExpression: "score > :num",
ExpressionAttributeValues: {
":num": currentScore,
":player": name,
":mail": email
},
ReturnValues: "UPDATED_NEW"
};
docClient.update(params, function(err, data) {
if (err) console.log(err);
else console.log(data);
});
}
What you want to do is a conditional update. This allows you to only the update the item in DynamoDB if a condition is met. In your case that condition would be, that the new score has to be higher than the existing score.
Such a conditional update would look like the following example. Note the ConditionExpression in there, which is responsible for only updating the item when the condition is met.
'use strict';
const aws = require('aws-sdk');
var newScore = 123;
var docClient = new AWS.DynamoDB.DocumentClient()
var params = {
TableName: "players",
Key: {
"email": "johndoe#gmail.com"
},
UpdateExpression: "set score = :num",
ConditionExpression: "score > :num",
ExpressionAttributeValues: {
":num": newScore
},
ReturnValues: "UPDATED_NEW"
};
docClient.update(params, function(err, data) {
if (err) console.log(err);
else console.log(data);
}
});
I want to query a dynamo db table for getting company id but the same table need a hash key so my query is something like this.
var optsq = {
'ConsistentRead': true,
'AttributesToGet': ['companyid'],
TableName : usertable,
Key : {
"userid" : {
"S" : usrname
},
"comapnyid" :{
"S":''
}
}
};
My query will only work if the query has the value of company id as well but i want to get company id how can i achive this. In my node js
dynamodb.getItem(optsq, function(err, compdata) {
if(err){
console.log(err);
}else{
console.log(compdata);
}
Instead of getItem, you should do a query, which allows you to specify only the userId.
var optsq = {
'ConsistentRead': true,
TableName : usertable,
KeyConditionExpression: "userid = :userid",
ExpressionAttributeValues: { ":userid": usrname },
ProjectionExpression: "companyid" }
Struggling to find an example of how to query a table to return rows with ids from a given list.
The query below throws on the inclusion of IN
var params = {
id: '7deb3df9-552b-47a4-aef3-ad601f141d50'
};
var p = {
TableName: 'players',
KeyConditionExpression: 'id IN (:id)',
ExpressionAttributeValues: buildQuery(params)
};
You can't use "IN" operator with KeyConditionExpression, please see details in this SO question
You may want to use batchGetItem instead of query, which is not so efficient though.
Here is how your params could look like:
var params = {
RequestItems: {
'players': {
Keys: [{
id: "7deb3df9-552b-47a4-aef3-ad601f141d50",
rangeKey: "<range key 1>" // <--- if your table has a range key, you must specify its value here
}, {
id: "<ANOTHER ID 2>",
rangeKey: "<range key 2>"
}, {
id: "<ANOTHER ID 3>",
rangeKey: "<range key 3>"
}]
}
}
};
dynamodbDoc.batchGet(params, function(err, data) {
});
I'm using NodeJS's aws-sdk and am trying to do an update such that if the item doesn't exist it will throw an error. I'm using the Expression API instead of the legacy one. Here is my contrived example that isn't working for me.
client.update({
TableName: 'User',
Key: {'_id': '10'},
UpdateExpression: 'SET username = :user, password = :pword',
ConditionalExpression: 'attribute_exists(#idKey) AND #idKey = :idVal',
ExpressionAttributeNames: {
'#idKey': '_id'
},
ExpressionAttributeValues: {
':idVal': '10',
':user': 'user10',
':pword': 'password10'
}}, function(err, data){
if(err) console.log(err);
else console.log(data);
});
ValidationException: Value provided in ExpressionAttributeNames unused in expressions: keys: {#idKey}
I've tried various other ConditionalExpressions both using attribute names and inserting the actual value into the expression. I'm beginning to think this is a bug. Using the legacy Expected->Exists with the legacy AttributeUpdate works but I am unable to demonstrate this feature with Expressions.
You are already narrowing down to the specific item where _id=10 with the Key parameter of your UpdateItemRequest. If an item does not exist, you cannot condition the UpdateItem call on a specific value of a key. Therefore, only the attribute_exists(#idKey) in the ConditionExpression is necessary.
The following code elicits the behavior you desire (I had to change table name to Images and primary key to Id to match the contents of the DynamoDB Local Shell tutorial.
var params = {
TableName: 'Image',
Key: { // The primary key of the item (a map of attribute name to AttributeValue)
'_id': 'dynamodb.png'
},
UpdateExpression: 'SET username = :user, password = :pword',
ConditionExpression: 'attribute_exists(#id)',
ExpressionAttributeValues: {
':user': 'user10',
':pword': 'password10'
},
ExpressionAttributeNames: {
'#id': '_id'
},
ReturnValues: 'ALL_NEW'
};
docClient.update(params, function(err, data) {
if (err) ppJson(err); // an error occurred
else ppJson(data); // successful response
});
As a reminder, please do not post any real password data here :)