I'm running through a lot of items in a DynamoDB table and if the item contains a certain field (which is a object), I want to set some properties on the object on that field.
I've tried two variations of the code, but both of them give me the following unspecified error
{
"errorType": "ConditionalCheckFailedException",
"errorMessage": "The conditional request failed",
"code": "ConditionalCheckFailedException",
"message": "The conditional request failed",
"time": "2020-08-29T11:44:11.703Z",
"requestId": "IAN8A31FN2F1HR0ORT1RMTH5ENVV4KQNSO5AEMVJF66Q9ASUAAJG",
"statusCode": 400,
"retryable": false,
"retryDelay": 26.45456917481479,
"stack": [
"ConditionalCheckFailedException: The conditional request failed",
" at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:51:27)",
" at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)",
" at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:78:10)",
" at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:688:14)",
" at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)",
" at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)",
" at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10",
" at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)",
" at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:690:12)",
" at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:116:18)"
]
}
Here's the code with named attributes
const itemParams = {
TableName: process.env.vehiclesTableName,
Key: { vehicleId },
UpdateExpression:
'set #learned.#versionId = :versionId, #learned.#fileFormat = :fileFormat',
ExpressionAttributeValues: {
':versionId': VersionId,
':fileFormat': fileFormat,
},
ConditionExpression: 'attribute_exists(#learned)',
ExpressionAttributeNames: {
'#learned': 'learned',
'#versionId': 'versionId',
'#fileFormat': 'fileFormat',
},
}
await db.update(itemParams).promise()
And without named attributes
const itemParams = {
TableName: process.env.vehiclesTableName,
Key: { vehicleId },
UpdateExpression:
'set learned.versionId = :versionId, learned.fileFormat = :fileFormat',
ExpressionAttributeValues: {
':versionId': VersionId,
':fileFormat': fileFormat,
},
ConditionExpression: 'attribute_exists(learned)',
}
await db.update(itemParams).promise()
They both behave the same.
The exception you're seeing is actually the expected behavior and indicates that the condition didn't evaluate to true. From the documentation:
ConditionalCheckFailedException
Message: The conditional request failed.
You specified a condition that evaluated to false. For example, you might have tried to perform a conditional update on an item, but the actual value of the attribute did not match the expected value in the condition.
As you're getting that ConditionalCheckFailedException exception, you're apparently trying to update an item which doesn't have a learned attribute.
Related
I have Hangfire that use Cosmos DB as database. When I choose Retries tab I get error:
An unhandled exception occurred while processing the request.
AggregateException: One or more errors occurred. (Response status code does not indicate success: NotFound (404); Substatus: 0; ActivityId: 68d632fc-8c5a-4624-80a5-7e9bc0d252f0; Reason: ({
"Errors": [
"Resource Not Found. Learn more: https://aka.ms/cosmosdb-tsg-not-found"
]
});)
System.Threading.Tasks.Task.Wait(int millisecondsTimeout, CancellationToken cancellationToken)
CosmosException: Response status code does not indicate success: NotFound (404); Substatus: 0; ActivityId: 68d632fc-8c5a-4624-80a5-7e9bc0d252f0; Reason: ({
"Errors": [
"Resource Not Found. Learn more: https://aka.ms/cosmosdb-tsg-not-found"
]
});
Microsoft.Azure.Cosmos.ResponseMessage.EnsureSuccessStatusCode()
When I try to make select statement on Cosmos DB to get items with key='retries':
SELECT * FROM c where c.key = 'retries' and c.value = 'b7ad3971-8647-4a29-a2a7-412e2da41527'
I get error in Cosmos DB:
Failed to query item for container hangfire:
Gateway Failed to Retrieve Query Plan: Message: {"errors":[{"severity":"Error","location":{"start":46,"end":51},"code":"SC1001","message":"Syntax error, incorrect syntax near 'value'."}]}
ActivityId: 4bc1d85a-4ea6-47c2-95d0-81bdde78f389, Microsoft.Azure.Documents.Common/2.11.0, Microsoft.Azure.Documents.Common/2.11.0
When I make select like this:
SELECT * FROM c where c.key = 'retries'
I can see result without error. Error occurs when I add AND c.value=... to the where clause.
I can't open retries tab on Hangfire dashboard.
Json in Cosmos looks like:
{
"key": "retries",
"value": "b7ad3971-8647-4a29-a2a7-412e2da41527",
"score": 0,
"created_on": 1611580578,
"type": 7,
"id": "b04c5c23-d324-45e1-acce-cdd2379c4073",
"_rid": "QO5WANzKkljY-gEAAAAAAA==",
"_self": "dbs/QO5WAA==/colls/QO5WANzKklg=/docs/QO5WANzKkljY-gEAAAAAAA==/",
"_etag": "\"2d01ed73-0000-0100-0000-600ec4a30000\"",
"_attachments": "attachments/",
"_ts": 1611580579
},
The reason you're getting this error is because value is a keyword. Please try the following query and it should work:
SELECT * FROM c where c.key = 'retries' and c["value"] = 'b7ad3971-8647-4a29-a2a7-412e2da41527'
I am learning to write CosmosDB stored procedures following the following information
Stored procedure docs
What I am trying to do is loop through a number of documents returned by a query and find the one that has the most exact match.
The flow is as follows
Check Start and End Date to make sure its a valid documents
1.5 Check that the input VariantNo is included in the Variants array in the document
Check if a user is included in the user array of the document OR if ALL is specified as a string in the array
Check if a store is included in the stores array OR if ALL is specified as a string in the stores array
The document looks as follows
{
"id": "12345",
"brand": "XXX",
"PromotionName": "Test Promo 1",
"PromotionType": "Deal",
"PromotionSticker": "Sticker 1",
"StartDate": "2020-05-14T00:00:00.1212122Z",
"EndDate": "2020-05-30T00:00:00.1212122Z",
"Variants": [
"0628462008001",
"0628462008002",
"0644324003002"
],
"Stores": [
"SE0623"
],
"Users": [
"ALL"
],
"DiscountInPercent": "30",
"RedPriceStores": null,
"CreatedDate": "20200515",
"CreatedBy": "SLAPI Promotions API ClientId: 123",
"UpdatedDate": null,
"UpdatedBy": null,
"Consumer": "YYYYY_V2",
"_rid": "HwVmAIFaOoEBAAAAAAAAAA==",
"_self": "dbs/HwVmAA==/colls/HwVmAIFaOoE=/docs/HwVmAIFaOoEBAAAAAAAAAA==/",
"_etag": "\"11005859-0000-0c00-0000-5ebe0f7e0000\"",
"_attachments": "attachments/",
"_ts": 1589514110
}
The beginnings of my stored procedure looks like this based on the template in CosmosDB
// SAMPLE STORED PROCEDURE
function getFinalPromotionPrice(item, store, user) {
var collection = getContext().getCollection();
// Query documents and take 1st item.
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT * FROM c WHERE c.StartDate <= (SELECT VALUE GetCurrentDateTime()) AND c.EndDate >= (SELECT VALUE GetCurrentDateTime())',
function (err, feed, options) {
if (err) throw err;
// Check the feed and if empty, set the body to 'no docs found',
// else take 1st element from feed
if (!feed || !feed.length) {
var response = getContext().getResponse();
response.setBody('no docs found');
}
else {
var response = getContext().getResponse();
var body = { prefix: prefix, feed: feed[0] };
response.setBody(JSON.stringify(body));
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
but I am getting this error when executing the stored procedure:
{"code":400,"body":{"code":"BadRequest","message":"Message: {\"Errors\":[\"Encountered exception while executing function. Exception = ReferenceError: 'prefix' is not defined\r\nStack trace: ReferenceError: 'prefix' is not defined\n at Anonymous function (script.js:20:13)\n at A
As you can check the error its expecting the "prefix" :
Exception = ReferenceError: 'prefix' is not defined
In the below line you are setting the value of prefix as "prefix" but you have not declared prefix anywhere in the code.
var body = { prefix: prefix, feed: feed[0] };
Change the above line to this if you don't require prefix in your SP body:
var body = { feed: feed[0] };
I am able to fetch the record from dynamo db and view the response successfully. I need to modify the fetched 'ACCOUNTNAME' attribute in the 'items' array and update the json and also update in dynamo db. Now when I try to update the fetched records I end up with the Invalid attribute value type exception.
I was trying to update it using the key with Array of Strings which is provided with code snippet also tried to update inside for loop using the individual string but both failed with same exception as
"statusCode": 400,
"body": {
"message": "Invalid attribute value type",
"error": {
"errorMessage": "ValidationException"
}
}
I tried to create params and update the call inside the for loop by setting the key as below,
Key: {
"UUID": {
"S": usersOfAccountFromDB.body.Items[key].UUID
}
,
"TYPE": {
"S": user
}
}
but also failed with the same exception.
Fetched Json from dynamo db
[
{
"DEFINITION": "914ba44a-8c26-4b60-af0f-96b6aa37efe6",
"UUID": "830a49cb-4ed3-41ae-b111-56714a71ab98",
"TYPE": "USER",
"RELATION": "01efd131-6a5d-4068-889e-9dba44262da5",
"ACCOUNTNAME": "Wolff LLC"
},
{
"DEFINITION": "1f60fded-323d-40e1-a7f8-e2d053b0bed0",
"UUID": "47db3bbe-53ac-4e58-a378-f42331141997",
"TYPE": "USER",
"RELATION": "01efd131-6a5d-4068-889e-9dba44262da5",
"ACCOUNTNAME": "Wolff LLC"
},
{
"DEFINITION": "05ddccba-2b6d-46bd-9db4-7b897ebe16ca",
"UUID": "e7290457-db77-48fc-bd1a-7056bfce8fab",
"TYPE": "USER",
"RELATION": "01efd131-6a5d-4068-889e-9dba44262da5",
"ACCOUNTNAME": "Wolff LLC"
},
.
.
.
.]
Now I tried to iterate the Json and setup UUID which is the key as the String array as below,
var userUUIDArray : string[] = [];
for (let key in usersOfAccountFromDB.body.Items) {
userUUIDArray.push(usersOfAccountFromDB.body.Items[key].UUID);
}
for (var uuid of userUUIDArray) {
console.log("UUID : " +uuid); // prints all the uuid
}
// Creating a parameter for the update dynamo db
var params = {
TableName: <tableName>,
Key: {
"UUID": {
"SS": userUUIDArray
}
,
"TYPE": {
"S": user
}
},
UpdateExpression: 'SET #ACCOUNTNAME = :val1',
ExpressionAttributeNames: {
'#ACCOUNTNAME': 'ACCOUNTNAME' //COLUMN NAME
},
ExpressionAttributeValues: {
':val1': newAccountName
},
ReturnValues: 'UPDATED_NEW',
};
//call the update of dynamodb
const result = await this.getDocClient().update(param).promise();
I get the error as below,
"body": {
"message": "Invalid attribute value type",
"error": {
"errorMessage": "ValidationException"
}
}
All the approaches failed with same above exception
The update operation which your code currently uses only allow a single item to be updated.
IIUC, you want to update multiple items with one API call. For this you need to use batchWrite operation. Keep in mind that you cannot update more than 25 items per invocation.
The origin of the error you are getting
Your code fails due to the use of "SS" in the UUID field. This field is of type string so you must use "S". Note however that since you're using the document client API you do not need to pass values using this notation. See this answer for further details.
I have resolved the issue now by running the update statement one by one using loop
for (let key in usersOfAccountFromDB.body.Items) {
var updateParam = {
TableName: process.env.AWS_DYNAMO_TABLE,
Key: {
UUID: usersOfAccountFromDB.body.Items[key].UUID,
TYPE: user
},
UpdateExpression: "SET #ACCOUNTNAME = :val1",
ExpressionAttributeNames: {
'#ACCOUNTNAME': 'ACCOUNTNAME'
},
ExpressionAttributeValues: {
":val1": newAccountName
},
ReturnValues: "UPDATED_NEW",
};
const result = await this.getDocClient().update(updateParam).promise();
}
I successfully update and delete an item from a StringSet in a dynamoDb table when called from my test app running on localhost.
I then upload the app to LightSail but now when I call the same function to update or delete an item it throws a ValidationException!:
{
"message": "Invalid UpdateExpression: Incorrect operand type for operator or
function; operator: DELETE, operand type: MAP",
"code": "ValidationException",
"time": "2018-01-03T13:20:14.919Z",
"requestId": "9HCQMH5RAUBRK1K7BNESNBUD5BVV4KQNSO5AEMVJF66Q9ASUAAJG",
"statusCode": 400,
"retryable": false,
"retryDelay": 10.381373865940402
}
Why? I have not made any changes to my code so why does this happen and how to solve it?
Here's the relevant code:
var documentClient = getDocumentClient();
var paramsSET = {
ExpressionAttributeNames:
{
"#StringSet": "Packages"
},
ExpressionAttributeValues:
{
":value": documentClient.createSet(['filler as SET cannot be empty',
app.packageName
])
},
Key:
{
"EmailAddress": app.emailAddress
},
ReturnValues: "ALL_NEW",
TableName: "Developers",
UpdateExpression: "ADD #StringSet :value"
// UpdateExpression: "DELETE #StringSet :value" ------ to delete value
};
// adds packagename to Packages SET in developers table - creates set if not exist
documentClient.update(paramsSET, function (err, data){}
I could not get it to work using the documentclient api.
finally used the old api and got it to work using dynamodb.updateItem see docs here
still have no idea why it works on localhost (accessing the same dynamodb tables) and not when live on LightSail!
I have this very basic model with just one field name that I want to validtate against a regex:
const Projects = new ProjectsCollection('projects');
Projects.schema = new SimpleSchema({
_id : {type: String, regEx: SimpleSchema.RegEx.Id},
name : {
type : String,
regEx: /^[a-zA-Z0-9]+((\s[a-zA-Z0-9]+)|(_[a-zA-Z0-9]+)|(-[a-zA-Z0-9]+)|(\.[a-zA-Z0-9]+))?$/
}
});
Projects.attachSchema(Projects.schema);
When the validation fails I get back a validation error saying that regex failed for Name which is undesirable for me because it's ambiguous and the user has no idea what exactly I need him to enter.
I tried adding the following with no success:
Projects.schema.messages({
"regEx name": [{
msg: "test error message"
}]
});
This one however..works but the problem is that I could have any other model with a name field and it will spit out the same error message for all of them (and I plan on having another model with a name field):
SimpleSchema.messages({
"regEx name": [{
msg: "test error message"
}]
});
I tried also with (no success):
SimpleSchema.messages({
"regEx projects.name": [{
msg: "test error message"
}]
});
I insert via methods and here's my insert code:
export const insert = new ValidatedMethod({
name : 'projects.insert',
mixins : [simpleSchemaMixin],
schema : Projects.simpleSchema().pick([
'name'
]),
schemaValidatorOptions: {
clean : true,
filter: false
},
run({name}) {
return Projects.insert({
name
}, null);
},
});
Any ideas on how am I supposed to configure my validation messages so that I can target them for specific fields?
See the documentation for the special case of regex messages:
In your case you should try:
Projects.schema.messages({
"regEx name": [
{
exp: /^[a-zA-Z0-9]+((\s[a-zA-Z0-9]+)|(_[a-zA-Z0-9]+)|(-[a-zA-Z0-9]+)|(\.[a-zA-Z0-9]+))?$/ ,
msg: "test error message"
}
]
});
This answer and question applies to v1 of meteor-simpl-schema
I had the same problem and this worked for me. I think that custom messages are instance based - are bound only to one simplSchema instance. Then in your validated-method, pick() will create a new SimplSchema instance, without your custom messages.
I needed to manually add a custom messages from the "parent" schema.
In your case like this:
const insertProjectSchema = Projects.schema.pick('name');
insertProjectSchema.messages(Projects.schema._messages);
export const insert = new ValidatedMethod({
name : 'projects.insert',
mixins : [simpleSchemaMixin],
schema : insertProjectSchema,
schemaValidatorOptions: {
clean : true,
filter: false
},
run({name}) {
return Projects.insert({
name
}, null);
},
});