Filter Expression based on a nested object DynamoDB AppSync - amazon-dynamodb

I'm trying to filter out a query based on a nested object (no array). I'm currently using AppSync and DynamoDB and the expression with expression values are executed correctly. But the filtering doesn't seem to work.
This is the sample data I'm trying to get (Filter by indicator.id):
Here's my query:
{
"version": "2017-02-28",
"operation": "Query",
"query": {
"expression": "pk = :pk and begins_with(sk, :sk)",
"expressionValues": {
":pk": { "S": "tenant:5fc30406-346c-42e2-8083-fda33ab6000a" },
":sk": {
"S": "school-year:2019-2020:grades:bVgA9abd:subject:m_kpc1Ae6:indicator:"
}
}
},
"filter": {
"expression": " contains(#indicatorId, :sk1) or contains(#indicatorId, :sk2) or contains(#indicatorId, :sk3)",
"expressionNames": { "#indicatorId": "indicator" },
"expressionValues": {
":sk1": {
"M": { "id": { "S": "07c658dd-999f-4e6f-95b8-c6bae422760a" } }
},
":sk2": {
"M": { "id": { "S": "0cf9f670-e284-4a93-b297-5e4a40c50228" } }
},
":sk3": { "M": { "id": { "S": "cd7902be-6512-4b47-b29d-40aff30c73e6" } } }
}
}
}
I've also tried:
{
"version": "2017-02-28",
"operation": "Query",
"query": {
"expression": "pk = :pk and begins_with(sk, :sk)",
"expressionValues": {
":pk": { "S": "tenant:5fc30406-346c-42e2-8083-fda33ab6000a" },
":sk": {
"S": "school-year:2019-2020:grades:bVgA9abd:subject:m_kpc1Ae6:indicator:"
}
}
},
"filter": {
"expression": " contains(#indicatorId, :sk1) or contains(#indicatorId, :sk2) or contains(#indicatorId, :sk3)",
"expressionNames": { "#indicatorId": "indicator.id" },
"expressionValues": {
":sk1": { "S": "07c658dd-999f-4e6f-95b8-c6bae422760a" },
":sk2": { "S": "0cf9f670-e284-4a93-b297-5e4a40c50228" },
":sk3": { "S": "cd7902be-6512-4b47-b29d-40aff30c73e6" }
}
}
}
I've also tried searching around StackOverflow, and Amazon forums and haven't found it directly to my problem:
How to filter by elements in an array (or nested object) in DynamoDB
Nested Query in DynamoDB returns nothing

Referring to this answer.enter link description here
According to DDB Nested Attributes doc, the filter expression should look like the following format:
"filter" : {
"expression" : "#path.#filter = :${fp}", ## filter path parent.target = :target
"expressionNames": {
"#path" : "${path}",
"#filter" : "${fp}"
},
"expressionValues" : {
":${fp}" : $util.dynamodb.toDynamoDBJson(${$target[$fp].eq}) ## :target : value to filter for
}
}

Related

ConditionalCheckFailedException: The conditional request failed (Nested field)

I have a DDB entry as below
RequestId:'1234567890' // Partition key
LastScanDateTime: '2023-01-12T11:00:00.111Z'
SubjectUpdateCounter: {
Maths: 1,
English: 1
}
I'm trying to update the entry and below is the update query.
{
"TableName": "EmpDetails",
"Key": {
"RequestId": {
"S": "1234567890"
}
},
"ConditionExpression": "(#subjectUpdateCounter > :subjectUpdateCounterLimit)",
"UpdateExpression": "ADD #subjectUpdateCounter :dec SET LastScanDateTime = :LastScanDateTime,",
"ExpressionAttributeValues": {
":dec": {
"N": "-1"
},
":LastScanDateTime": {
"S": "2023-02-13T18:14:52.143Z"
},
":subjectUpdateCounterLimit": {
"N": "0"
}
},
"ReturnValues": "NONE",
"ExpressionAttributeNames": {
"#subjectUpdateCounter": "SubjectUpdateCounter.Maths"
}
}
Getting below error
ConditionalCheckFailedException: The conditional request failed
....
....
'$fault': 'client',
'$metadata': {
httpStatusCode: 400,
requestId: '12345ygfsdfagagdf',
extendedRequestId: undefined,
cfId: undefined,
attempts: 1,
totalRetryDelay: 0
},
__type: 'com.amazonaws.dynamodb.v20120810#ConditionalCheckFailedException'
}
My current value in SubjectUpdateCounter.Maths is greater than 0, so the condition should succeed and this query should decrement the value of SubjectUpdateCounter.Maths to 0.
Why is the query throwing the above exception?
Your issue is here:
"ExpressionAttributeNames": {
"#subjectUpdateCounter": "SubjectUpdateCounter.Maths"
}
This means DynamoDB is looking for an attribute named "SubjectUpdateCounter.Maths" but there is none, as its a nested value you are looking for.
Your request should look like the following:
{
"TableName": "EmpDetails",
"Key": {
"RequestId": {
"S": "1234567890"
}
},
"ConditionExpression": "(#subjectUpdateCounter.#maths > :subjectUpdateCounterLimit)",
"UpdateExpression": "ADD #subjectUpdateCounter.#maths :dec SET LastScanDateTime = :LastScanDateTime,",
"ExpressionAttributeValues": {
":dec": {
"N": "-1"
},
":LastScanDateTime": {
"S": "2023-02-13T18:14:52.143Z"
},
":subjectUpdateCounterLimit": {
"N": "0"
}
},
"ReturnValues": "NONE",
"ExpressionAttributeNames": {
"#subjectUpdateCounter": "SubjectUpdateCounter",
"#maths":"Maths"
}
}

DynamoDB how to filter by attributes of array items?

{
"id":{"N": "1"},
"attributes": {
"L": [
{
"M": {
"name": { "S": "AA" }
}
},
{
"M": {
"name": { "S": "BB" }
}
}
]
}
},
{
"id":{"N": "1"},
"attributes": {
"L": [
{
"M": {
"name": { "S": "BB" }
}
}
]
}
}
With the above data in the same partition( id as the partition key), How can I find records where any of attributes has name = 'BB' ?
I can filter by Nth item, for example.
KeyConditionExpression: 'id = :myId',
ExpressionAttributeValues: {'myId':{N:'1'},'myValue':{S:'BB'}},
ExpressionAttributeNames:{'#name': 'name'},
FilterExpression: 'attributes[0].#name=:myValue'
This would return only 2nd item. But is there a way to filter by ANY item in the array? It should return both records.
Tried set FilterExpression to attributes[*].#name=:myValue or attributes.#name=:myValue, neither works.

How to use multiple if/then in JSON schema

I have a JSON schema defined as below -
{
"type": "object",
"properties": {
"prop1": {
"type": "string"
},
"prop2": {
"type": "string"
},
"prop3": {
"type": "string"
},
"prop4": {
"type": "string"
}
},
"anyOf": [
{
"if": {
"properties": {
"prop1": {
"const": "v1"
},
"prop2": {
"const": "v2"
}
}
},
"then": {
"required": [
"prop1",
"prop2",
"prop3"
]
}
},
{
"if": {
"properties": {
"prop1": {
"const": "v11"
},
"prop2": {
"const": "v22"
}
}
},
"then": {
"required": [
"prop1",
"prop2",
"prop4"
]
}
}
],
"required": [
"prop1",
"prop2"
]
}
A few scenarios i would like to validate -
{
"prop1": "aaa"
}
//should say prop2 is required --This works
{
"prop1": "aaa",
"prop2": "bbb"
}
//should validate to true --This works
{
"prop1": "v1"
"prop2": "v2"
}
//should say prop3 is required --This DOESN'T work
{
"prop1": "v11"
"prop2": "v22"
}
//should say prop4 is required --This DOESN'T work
Could someone please help me how to fix the above 2 test cases that doesnt work?
You need to change your anyOf to a allOf, to make sure both conditions are checked.
Due to the way you have written your if conditions, only one of them can be true at a time, so for one or the other of them (or both), the else clause will be executed, but you haven't provided an else clause, so it defaults to true, so at least one of the anyOf clauses will be true, so anyOf is true.

AWS Console Dynamodb scan search payload attribute

when I scan the aws dynamodb with the attribute name as "Asset_Name" string equals "MakingofaMusicVideo_HD", I am not getting any hits. But the payload contains the field. What's the best way to search for quick search.
Are there any other tools or projects which has a ux that enables users to search quickly?
"Asset_Name": {"S": "MakingofaMusicVideo_HD"}
Below is the payload in dynamodb
"payload": {
"M": {
"CableLabArray": {
"M": {
"ADI": {
"M": {
"Metadata": {
"M": {
"__custom:APP_DATA:2": {
"M": {
"_attributes": {
"M": {
"App": {
"S": "MOD"
},
"Value": {
"S": "CableLabsVOD1.1"
},
"Name": {
"S": "Metadata_Spec_Version"
}
}
}
}
},
"AMS": {
"M": {
"_attributes": {
"M": {
"Asset_ID": {
"S": "XXXXXXXXXXXXXXXXX"
},
"Version_Minor": {
"S": "1"
},
"Description": {
"S": "Making of a Music Video"
},
"Provider_ID": {
"S": "hs90s.ca"
},
"Creation_Date": {
"S": "2020-04-05"
},
"verb": {
"S": "EMPTY"
},
"Product": {
"S": "MOD"
},
"Version_Major": {
"S": "1"
},
"Asset_Name": {
"S": "MakingofaMusicVideo_HD"
},
"Asset_Class": {
"S": "package"
},
"Provider": {
"S": "HS90s"
}
}
}
}
}```
While DynamoDb supports storing complex attributes (e.g. maps, lists, sets, any combination of these), it does not offer search capabilities across complex attributes. You either need to store it as a top level attribute, or work it into the primary key.

Updating item in DynamoDB fails for the UpdateExpression syntax

My table data looks like below one
{
"id": {
"S": "alpha-rocket"
},
"images": {
"SS": [
"apple/value:50",
"Mango/aa:284_454_51.0.0",
"Mango/bb:291",
"Mango/cc:4"
]
},
"product": {
"S": "fruit"
}
}
Below is my code to update table. The variables I am passing to function has values product_id has alpha-rocket, image_val has 284_454_53.0.0 and image has Mango/aa:284_454_53.0.0.
I am trying to update value of Mango/aa from 284_454_51.0.0 to 284_454_53.0.0 but getting an error "The document path provided in the update expression is invalid for update"
def update_player_score(product_id, image_val, image):
dynamo = boto3.resource('dynamodb')
tbl = dynamo.Table('<TableName>')
result = tbl.update_item(
expression_attribute_names: {
"#image_name" => "image_name"
},
expression_attribute_values: {
":image_val" => image_val,
},
key: {
"product" => "fruit",
"id" => product_id,
},
return_values: "ALL_NEW",
table_name: "orcus",
update_expression: "SET images.#image_val = :image_val",
}
Is there a way to update the value of Mango/aa or replace full string "Mango/aa:284_454_51.0.0" to "Mango/aa:284_454_53.0.0"
You cannot update a string in a list by matching the string. If you know the index of it you can replace the value of the string by index:
SET images[1] = : image_val
It seems like maybe what you want is not a list of strings, but another map. So instead of your data looking like it does you'd make it look like this, which would allow you to do the update you're looking for:
{
"id": {
"S": "alpha-rocket"
},
"images": {
"M": {
"apple" : {
"M": {
"value": {
"S": "50"
}
},
"Mango" : {
"M": {
"aa": {
"S": "284_454_51.0.0"
},
"bb": {
"S": "291"
},
"cc": {
"S": "4"
}
}
}
},
"product": {
"S": "fruit"
}
}
I would also consider putting the different values in different "rows" in the table and using queries to build the objects.

Resources