I'm trying to update an Item in my Dynamodb Table +Users+. I have tried many different ways but I always received the same error message:
The provided key element does not match the schema
The creation of an Item works, as well as a query but not the update. When I check on DynamoDB the user is well created:
{
"email": "test#email.com",
"password": "123",
"registration": 1460136902241,
"verified": false
}
Here is the table information:
Table name: Users
Primary partition key: email (String)
Primary sort key: registration (Number)
Here is the code (called from lambda):
exports.handler = function(event, context)
{
var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "Users",
Item:{
email: "test#email.com",
password: "123",
verified: false,
registration: (new Date()).getTime(),
}
};
// Create the user.
docClient.put(params, function(err, data)
{
if (err)
{
context.fail("Put failed...");
return;
}
var params = {
TableName: "Users",
Key: { email : "test#email.com" },
AttributeUpdates: {
verified: {
Action: "PUT",
Value: true
}
}
};
// Update the user.
docClient.update(params, function(err, data)
{
if (err)
{
console.log(JSON.stringify(err));
context.fail(JSON.stringify(err));
return;
}
context.succeed("User successfully updated.");
});
});
};
Do you have any idea of what could be wrong in my code?
You are only providing half of your primary key. Your primary key is a combination of the partition key and range key. You need to include the range key in your Key attribute in the update parameters.
For others who have faced the same challenge and the issue is not fixed by above answers, it is always better to double check the data type of the value being updated, in my case the primary key was expecting a Number and I was trying to update with a string. Silly me
My issue was with the Node SDK for deletes, where the documentation says to provide in format:
... {Key: {'id': {S: '123'}}} ...
Which does not appear to work with the aws-sdk ^2.1077.0. This seems to work:
... {Key: {'id': '123'}} ...
My checklist when facing this issue:
Check that the name and type of your key correspond to what you have in the database.
Use corresponding attributes to make it explicit. E.g. use #DynamoDBHashKey(attributeName = "userId") in Java to indicate the partition key named userId.
Ensure that only one field or getter marked as partition key in your class.
Please, add more if you know in the comments.
I was doing BatchGetItem, then streamed it to BatchWriteItem (Delete). DeleteItem didn't like it got all attributes from the object instead of only partition and sort key.
Gathering all answers:
mismatch in an attribute name
mismatch in attribute type
half key provided
unnecessary additional keys
Related
I'm trying to update an Item in my Dynamodb Table +Users+. I have tried many different ways but I always received the same error message:
The provided key element does not match the schema
The creation of an Item works, as well as a query but not the update. When I check on DynamoDB the user is well created:
{
"email": "test#email.com",
"password": "123",
"registration": 1460136902241,
"verified": false
}
Here is the table information:
Table name: Users
Primary partition key: email (String)
Primary sort key: registration (Number)
Here is the code (called from lambda):
exports.handler = function(event, context)
{
var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "Users",
Item:{
email: "test#email.com",
password: "123",
verified: false,
registration: (new Date()).getTime(),
}
};
// Create the user.
docClient.put(params, function(err, data)
{
if (err)
{
context.fail("Put failed...");
return;
}
var params = {
TableName: "Users",
Key: { email : "test#email.com" },
AttributeUpdates: {
verified: {
Action: "PUT",
Value: true
}
}
};
// Update the user.
docClient.update(params, function(err, data)
{
if (err)
{
console.log(JSON.stringify(err));
context.fail(JSON.stringify(err));
return;
}
context.succeed("User successfully updated.");
});
});
};
Do you have any idea of what could be wrong in my code?
You are only providing half of your primary key. Your primary key is a combination of the partition key and range key. You need to include the range key in your Key attribute in the update parameters.
For others who have faced the same challenge and the issue is not fixed by above answers, it is always better to double check the data type of the value being updated, in my case the primary key was expecting a Number and I was trying to update with a string. Silly me
My issue was with the Node SDK for deletes, where the documentation says to provide in format:
... {Key: {'id': {S: '123'}}} ...
Which does not appear to work with the aws-sdk ^2.1077.0. This seems to work:
... {Key: {'id': '123'}} ...
My checklist when facing this issue:
Check that the name and type of your key correspond to what you have in the database.
Use corresponding attributes to make it explicit. E.g. use #DynamoDBHashKey(attributeName = "userId") in Java to indicate the partition key named userId.
Ensure that only one field or getter marked as partition key in your class.
Please, add more if you know in the comments.
I was doing BatchGetItem, then streamed it to BatchWriteItem (Delete). DeleteItem didn't like it got all attributes from the object instead of only partition and sort key.
Gathering all answers:
mismatch in an attribute name
mismatch in attribute type
half key provided
unnecessary additional keys
I don't want to create a property for loading relation into it (as shown in all the examples). The only thing I need is to have an explicit foreign key property so that the migration will be able to create appropriate constraints for it in the database. The closest decorator to the one I need is #RelationId but it still requires the presence of a property of the relational class.
For clarity let's take the example from the documentation:
#Entity()
export class Post {
#ManyToOne(type => Category)
category: Category;
#RelationId((post: Post) => post.category) // it still requires the presence of the `category` proeprty
categoryId: number;
}
I don't need the category property here. I want to have the categoryId property and mark it as foreign key to Category.Id. It should look like this:
#Entity()
export class Post {
#ForeignKey((category: Category) => category.Id) // it's a foreign key to Category.Id
categoryId: number;
}
Is it possible?
"I need is to have an explicit foreign key property"...
No, you could not. TypeOrm will automatically create foreign key property when you use #ManyToOne decorator. Just combine #ManyToOne and #JoinColumn decorators together like this:
#ManyToOne(type => Category)
#JoinColumn({ name: 'custom_field_name_if_you_want' })
category: Category;
Maybe you can create and write your own migration and use it like this :
const queryRunner = connection.createQueryRunner();
await queryRunner.createTable(new Table({
name: "question",
columns: [
{
name: "id",
type: "int",
isPrimary: true
},
{
name: "name",
type: "varchar",
}
]
}), true);
await queryRunner.createTable(new Table({
name: "answer",
columns: [
{
name: "id",
type: "int",
isPrimary: true
},
{
name: "name",
type: "varchar",
},
{
name: "questionId",
isUnique: connection.driver instanceof CockroachDriver, // CockroachDB requires UNIQUE constraints on referenced columns
type: "int",
}
]
}), true);
// clear sqls in memory to avoid removing tables when down queries executed.
queryRunner.clearSqlMemory();
const foreignKey = new TableForeignKey({
columnNames: ["questionId"],
referencedColumnNames: ["id"],
referencedTableName: "question",
onDelete: "CASCADE"
});
await queryRunner.createForeignKey("answer", foreignKey);
This code snippet is extracted from the functional test of type orm and you can use it to create your own constraint on the database I think.
It's actually possible to do so:
#Entity()
export class Post {
// this will add categoryId
#ManyToOne(type => Category)
category: Category;
// and you can use this for accessing post.categoryId
// only column you mark with #Column decorator will be mapped to a database column
// Ref: https://typeorm.io/#/entities
categoryId: number;
}
The added categoryId won't be mapped to column and will then be use for setting explicitly the id or for accessing its value as in:
post.categoryId = 1;
// or
const id = post.categoryId
Check with these two places Auth module(JwtModule.register()) and JWT strategy(super({...})). Make sure you have secret /secretOrKey is set to the same key. In my case "secret: process.env.JWT_SECRET_KEY" & "secretOrKey: process.env.JWT_SECRET_KEY"
I have encountered the same problem recently.
I still use the Entity but only with the primary key value of the referenced entity.
i.e. I do not query the database for the referenced entity.
Suppose your category entity looks like this:
#Entity()
export class Category{
#PrimaryGeneratedColumn()
id: number;
// ... other stuff
}
Now using your codes as example.
Dircely assigning relation using a foreign key value would be like.
// You wish to assign category #12 to a certain post
post.category = { id: 12 } as Category
I have the following table in my DynamoDB
Thread (id, userId, content)
With id being the primary key. I have not defined any sort key.
Now i need to retrieve a result based on the userId .. in short i need all the records in table containing a specific userId
userId = '123';
let queryParams = {
TableName: tableName,
ExpressionAttributeNames: {
'#userid': 'userid'
},
ExpressionAttributeValues: {
':userid': userId
},
KeyConditionExpression: "#userid = :userid"
}
dynamodb.query(queryParams, (err, data) => {
console.log(err);
console.log(data);
});
when i run this, i get an error
Could not load items: ValidationException: Query condition missed key schema element: id
Can someone please let me know how can i query for all records containing the userId '123'??
To do this, you will need to add a Global Secondary Index to your table that has userId as the primary key. Then you can query that index directly.
You must also include the name of the index in the query request (source).
When I tried to update a item in dynamodb the following error appears:
var docClient = new AWS.DynamoDB.DocumentClient();
function updateItem() {
var table = "Bicycle";
var params = {
TableName:table,
Key:{
warrantyDate: "2018/10/23",
warrantyStatus: "Active"
},
UpdateExpression: "set warrantyStatus = :r",
ExpressionAttributeValues:{
":r":"Inactive"
},
ReturnValues:"UPDATED_NEW"
};
docClient.update(params, function(err, data) {
if (err) {
alert("Unable to update item");
alert(err);
} else {
alert("UpdateItem succeeded");
}
});
}
when I call this function I received this exception:
ValidationException: The provided key element does not match the schema
how can i fix this?
The problem is that you KEY attribute value does not match your primary partition key on your dynamodb table.
When updating an item, you need to specify the single key that maps to your primary key on the dynamodb table. There should only be one attribute in the Key field. You are trying to find a key that is both the warrantyDate and warrantyStatus. Make sure you're specifying the correct key that maps to your dynamodb configuration.
If you're trying to update multiple items, you need to use another function, as doClient.update() only updates a single row that matches your key to the primary index on the table.
I have a table in Dynamodb and I'm trying to get an item (using docClient.get) by naming a Global Secondary Index but I'm getting the error:
The provided key element does not match the schema
And here's my query:
docClient
.get({
TableName: 'table',,
IndexName: 'gsi_table',
Key: { primary_key }
})
But then I looked at the get documentation and it does not have an IndexName property. So I thought maybe I should name the GSI instead of the table name:
docClient
.get({
TableName: 'gsi_table',
Key: { primary_key }
})
But then I faced:
Requested resource not found
which means gsi_table is not recognized as a global table. So my question is, having the list of operations:
batchGet
batchWrite
createSet
delete
get
put
query
scan
update
which ones support GSI and LSI? And also, if you want to retrieve one specific item using a GSI, which operation should you use? If I use query, am I actually doing things as fast/cheap as possible?
Secondary indexes are for Query and Scan operations only. So, if you must use a global (or local) secondary index, then Query would be faster than Scan, of course.
To access your "single" item, you can use data.Items[0]. For example:
const params = {
TableName: "TABLE_NAME",
IndexName: "INDEX_NAME",
KeyConditionExpression: "INDEX_KEY = :k",
ExpressionAttributeValues: {
":k": some_value
}
};
docClient.query(params, (err, data) => {
if (err) {
console.log(err);
} else {
const myItem = data.Items[0];
}
});