dynamodb UpdateItem json payload - amazon-dynamodb

I am using the AWS service proxy to expose DynamoDB as API. For PutItem it works fine, but I don't have idea how to update a array of object.
Below "paymentDetail" is the list of Map, I can post to DynamoDB, but I failed for update the JSON payload. Not sure DynamoDB support this or not, I always got this message:
{"__type": "com.amazon.coral.service#SerializationException"}
Can anybody share your ideas how to use mapping template to update JSON payload? Thanks in advance.
Here is my code, please advise and help.Please kindly let me know in case that the information is not sufficient.
--------- Request Method for UpdateItem ------------
{
"TableName": "claim",
"Key": {
"claimNumber": {
"S": "$input.params("claimNumber")"
}
},
"UpdateExpression": "set claimStatus = :claimStatus, statusUpdateDate = :statusUpdateDate, netClaimAmount = :netClaimAmount, paymentDetail = :paymentDetail, updatedAt = :updatedAt",
"ConditionExpression": "claimNumber = :claimNumber",
"ExpressionAttributeValues": {
":claimNumber": {"S": "$input.params("claimNumber")"},
":claimStatus": {"S": "$input.path("$.claimStatus")"},
":statusUpdateDate": {"S": "$input.path("$.statusUpdateDate")"},
":netClaimAmount": {"N": "$input.path("$.netClaimAmount")"},
":paymentDetail": {"L": "$input.path("$.paymentDetail")"},
":updatedAt": {"S": "$input.path("$.updatedAt")"}
},
"ReturnValues": "UPDATED_NEW"
}
----------test data for UpdateItem---------
{
"claimNumber": "000-00-000959",
"updatedAt":"2017-09-10",
"claimStatus": "close",
"statusUpdateDate": "2017-09-13",
"netClaimAmount": 60000000,
"paymentDetail": [
{
"coverage": "AAA",
"claimPaymentDate": "2017-09-03",
"claimAmount": "10000000",
"costCategory": "1",
"costType": "A"
},
{
"coverage": "BBB",
"claimPaymentDate": "2017-09-03",
"claimAmount": "20000000",
"costCategory": "2",
"costType": "B"
},
{
"coverage": "CCC",
"claimPaymentDate": "2017-09-03",
"claimAmount": "30000000",
"costCategory": "3",
"costType": "C"
}
]
}
---PutItem for your information---
#set($inputRoot = $input.path('$'))
{
"TableName": "claim",
"Item": {
"claimNumber": {
"S": "$input.path("$.claimNumber")"
},
"policyNumber": {
"S": "$input.path("$.policyNumber")"
},
"productName": {
"S": "$input.path("$.productName")"
},
"lossDate": {
"S": "$input.path("$.lossDate")"
},
"lossTime": {
"S": "$input.path("$.lossTime")"
},
"reportedDate": {
"S": "$input.path("$.reportedDate")"
},
"lossCause": {
"S": "$input.path("$.lossCause")"
},
"description": {
"S": "$input.path("$.description")"
},
"prefectureCode": {
"S": "$input.path("$.prefectureCode")"
},
"city": {
"S": "$input.path("$.city")"
},
"address": {
"S": "$input.path("$.address")"
},
"reportedByType": {
"S": "$input.path("$.reportedByType")"
},
"createdAt": {
"S": "$input.path("$.createdAt")"
},
"updatedAt": {
"S": "$input.path("$.updatedAt")"
},
"claimImageId": {
"S": "$input.path("$.claimImageId")"
},
"contact": {
"M": {
"lastName": {
"S": "$input.path("$.contact.lastName")"
},
"firstName": {
"S": "$input.path("$.contact.firstName")"
},
"postCode": {
"S": "$input.path("$.contact.postCode")"
},
"prefectureCode": {
"S": "$input.path("$.contact.prefectureCode")"
},
"city": {
"S": "$input.path("$.contact.city")"
},
"address": {
"S": "$input.path("$.contact.address")"
},
"homePhone": {
"S": "$input.path("$.contact.homePhone")"
},
"email": {
"S": "$input.path("$.contact.email")"
}
}
},
"claimStatus": {
"S": "$input.path("$.claimStatus")"
},
"statusUpdateDate": {
"S": "$input.path("$.statusUpdateDate")"
},
"netClaimAmount": {
"N": "$input.path("$.netClaimAmount")"
},
"paymentDetail": {
"L":[
#foreach($elem in $inputRoot.paymentDetail){
"M": {
"coverage": {
"S": "$elem.coverage"
},
"claimPaymentDate": {
"S": "$elem.claimPaymentDate"
},
"claimAmount": {
"S": "$elem.claimAmount"
},
"costCategory": {
"S": "$elem.costCategory"
},
"costType": {
"S": "$elem.costType"
}
}
}#if($foreach.hasNext),#end
#end
]
}
}
}

Your body mapping template seems to have issues.
Please see below the corrected one.
#set($inputRoot = $input.path('$'))
{
"TableName": "claim",
"Key": {
"claimNumber": {
"S": "$input.path("$.claimNumber")"
}
},
"UpdateExpression": "set claimStatus = :claimStatus, statusUpdateDate = :statusUpdateDate, netClaimAmount = :netClaimAmount, paymentDetail = :paymentDetail, updatedAt = :updatedAt",
"ConditionExpression": "claimNumber = :claimNumber",
"ExpressionAttributeValues": {
":claimNumber": {"S": "$input.path("$.claimNumber")"},
":claimStatus": {"S": "$input.path("$.claimStatus")"},
":statusUpdateDate": {"S": "$input.path("$.statusUpdateDate")"},
":netClaimAmount": {"N": "$input.path("$.netClaimAmount")"},
":updatedAt": {"S": "$input.path("$.updatedAt")"},
":paymentDetail": {
"L":[
#foreach($elem in $inputRoot.paymentDetail){
"M": {
"coverage": {
"S": "$elem.coverage"
},
"claimPaymentDate": {
"S": "$elem.claimPaymentDate"
},
"claimAmount": {
"S": "$elem.claimAmount"
},
"costCategory": {
"S": "$elem.costCategory"
},
"costType": {
"S": "$elem.costType"
}
}
}#if($foreach.hasNext),#end
#end
]
}
},
"ReturnValues": "UPDATED_NEW"
}

Related

SABRE Hotel Book request is missing TravelItineraryRead in the response

I'm having an issue performing the following SABRe hotel book in the CRT environment using an orchestrated workflow.
{
"CreatePassengerNameRecordRQ": {
"version": "2.3.0",
"TravelItineraryAddInfo": {
"CustomerInfo": {
"ContactNumbers": {
"ContactNumber": [
{
"NameNumber": "1.1",
"Phone": "17805555555",
"PhoneUseType": "H"
}
]
},
"Email": [
{
"Address": "chris#test.com",
"Type": "TO"
}
],
"PersonName": [
{
"NameNumber": "1.1",
"PassengerType": "ADT",
"GivenName": "Chris",
"Surname": "test"
}
]
}
},
"HotelBook": {
"BookingInfo": {
"BookingKey": "5d07cdba-0123-4510-9f9a-5257973b5f98",
"RequestorID": "SG000000"
},
"Rooms": {
"Room": [
{
"Guests": {
"Guest": [
{
...
}
]
},
"RoomIndex": 1
}
]
},
"PaymentInformation": {
"FormOfPayment": {
"PaymentCard": {
"PaymentType": "CC",
"CardCode": "VI",
"CardNumber": "4111111111111111",
"ExpiryMonth": 3,
"ExpiryYear": "2024",
"FullCardHolderName": {
"FirstName": "Chris",
"LastName": "test",
"Email": "chris#test.com"
},
"CSC": "013",
"Address": {
...
},
"Phone": {
"PhoneNumber": "17805555555"
}
}
},
"Type": "GUARANTEE"
},
"POS": {
"Source": {
"RequestorID": {
"Type": 5,
"Id": "XXX",
"IdContext": "IATA"
},
"AgencyAddress": {
"AddressLine1": "1 Lincoln Blvd",
"CountryName": {
"Code": "US"
}
},
"AgencyName": "Flying Wings",
"ISOCountryCode": "US",
"PseudoCityCode": "1MNJ"
}
}
},
"PostProcessing": {
"EndTransaction": {
"Source": {
"ReceivedFrom": "Flying Wings Web"
},
"Email": {
"Ind": true
}
}
}
}
}
The response I get is:
{
"CreatePassengerNameRecordRS": {
"ApplicationResults": {
"status": "Complete",
"Success": [
{
"timeStamp": "2021-03-08T01:18:50.544-06:00"
}
]
},
"ItineraryRef": {
"ID": "VKIJSI"
}
},
"Links": [
]
}
So a successful booking however I am expecting a TravelItineraryRead returned in the response and am not getting one. Am I missing something in the request?
Thanks.
try redisplaing the newly created reservation.
"RedisplayReservation": {
"waitInterval": 100
}
that should include the itinerary in the response

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.

dynamodb UpdateItem using API Gateway as Proxy, error

I am using the AWS API Gateway as proxy to expose DynamoDB API. the UpdateItem mapping is not working, it return:
{
"__type": "com.amazon.coral.service#SerializationException"
}
Below is the mapping template and the payload:
{
"TableName": "registros",
"Key": {
"Pk": {
"S": "$input.path('$.Pk')"
},
"Sk": {
"S": "$input.path('$.Sk')"
}
},
"UpdateExpression": "set intenciones = :intenciones",
"ConditionExpression": "Pk = :Pk, Sk = :Sk,",
"ExpressionAttributeValues": {
":Pk": {"S": "$input.path('$.Pk')"},
":Sk": {"S": "$input.path('$.Sk')"},
":intenciones": {"S": "$input.path('$.intenciones')"},
},
"ReturnValues": "UPDATED_NEW"
}
Payload:
{
"Pk":"DemandaProd",
"Sk":"raerytre#22",
"intenciones":"news"
}
You don't need ConditionExpression since it's implied with Key that you'll be matching on the Pk and Sk. Try this:
{
"TableName": "registros",
"Key": {
"Pk": {
"S": "$input.path('$.Pk')"
},
"Sk": {
"S": "$input.path('$.Sk')"
}
},
"UpdateExpression": "set intenciones = :intenciones",
"ExpressionAttributeValues": {
":intenciones": { "S": "$input.path('$.intenciones')" }
},
"ReturnValues": "UPDATED_NEW"
}

DynamoDB UpdateException: Type mismatch for attribute to update

I have the following record in DynamoDB:
{
"BusinessNo": {
"N": "12345"
},
"Metadata": {
"M": {
"MimeType": {
"S": "audio/wav"
},
"FileName": {
"S": "00032329.wav"
},
"CustomC": {
"S": "baz"
},
"CustomA": {
"S": "foo"
},
"CustomB": {
"S": "bar"
},
"Size": {
"S": "3992020323"
}
}
},
"Id": {
"S": "f0de8af3-a7f5-4d9b-ad5d-b2f150abd15e"
},
"Revision": {
"N": "2"
}
}
But when I submit the following using the update method of DynamoDB.DocumentClient from the nodejs AWS SDK (I have also tried add instead of set):
{
"TableName": "Storage_FileMetadata",
"Key": {
"Id": "f0de8af3-a7f5-4d9b-ad5d-b2f150abd15e",
"BusinessNo": "12345"
},
"ExpressionAttributeNames": {
"#m": "Metadata",
"#k": "CustomD",
"#r": "Revision"
},
"ExpressionAttributeValues": {
":r": 4,
":v": "doo-wop"
},
"UpdateExpression": "set #m.#k = :v",
"ConditionExpression": "#r < :r"
}
I get the following exception:
{
"message": "Type mismatch for attribute to update",
"code": "ValidationException",
"time": "2016-11-11T18:55:01.543Z",
"requestId": "b9d78c87-1c4d-400a-8968-d761b657cd53",
"statusCode": 400,
"retryable": false,
"retryDelay": 0
}
I think I'm missing something about adding/updating nested attributes but after reading the docs I can't figure out what.
Seems that you need to send the value "BusinessNo": "12345" as a number
"Key": {
"Id": "f0de8af3-a7f5-4d9b-ad5d-b2f150abd15e",
"BusinessNo": 12345
}

Body Mapping Template + API Gateway

So I'm trying to set up a basic POST to a API Post Method I made that's connected to a simple dynamodb. I have the following Body Mapping Template below:
{
"TableName": "bars",
"Item": {
"barid": {
"S": "$input.path('$.barid')"
},
"phone": {
"S": "$input.path('$.phone')"
},
"location": {
"S": "$input.path('$.location')"
},
"happyhour": {
"L": [
{
"M": {
"Time": {
"S": "$input.path('$.Time')"
},
"Deal": {
"S": "$input.path('$.Deal')"
},
"Day": {
"S": "$input.path('$.Day')"
}
}
},
{
"M": {
"Time": {
"S": "$input.path('$.Time')"
},
"Deal": {
"S": "$input.path('$.Deal')"
},
"Day": {
"S": "$input.path('$.Day')"
}
}
},
{
"M": {
"Time": {
"S": "$input.path('$.Time')"
},
"Deal": {
"S": "$input.path('$.Deal')"
},
"Day": {
"S": "$input.path('$.Day')"
}
}
},
{
"M": {
"Time": {
"S": "$input.path('$.Time')"
},
"Deal": {
"S": "$input.path('$.Deal')"
},
"Day": {
"S": "$input.path('$.Day')"
}
}
},
{
"M": {
"Time": {
"S": "$input.path('$.Time')"
},
"Deal": {
"S": "$input.path('$.Deal')"
},
"Day": {
"S": "$input.path('$.Day')"
}
}
},
{
"M": {
"Time": {
"S": "$input.path('$.Time')"
},
"Deal": {
"S": "$input.path('$.Deal')"
},
"Day": {
"S": "$input.path('$.Day')"
}
}
},
{
"M": {
"Time": {
"S": "$input.path('$.Time')"
},
"Deal": {
"S": "$input.path('$.Deal')"
},
"Day": {
"S": "$input.path('$.Day')"
}
}
}
]
},
"name": {
"S": "$input.path('$.name')"
}
}
}
Here is what I'm testing the post statement with:
{
"barid": {
"S": "005"
},
"happyhour": {
"L": [{
"M": {
"Time": {
"S": "11AM-9AM"
},
"Deal": {
"S": "$3 Mimosas; $3 Bloody Marys"
},
"Day": {
"S": "Sunday"
}
}
}, {
"M": {
"Time": {
"S": "4PM - 9PM"
},
"Deal": {
"S": "$4 Margaritas, Corona, Corona Light; $3 Bud Light Lime"
},
"Day": {
"S": "Monday"
}
}
}, {
"M": {
"Time": {
"S": "4PM-9PM"
},
"Deal": {
"S": "1/2 Price Burgers; $2 Bud and Bud Light Drafts"
},
"Day": {
"S": "Tuesday"
}
}
}, {
"M": {
"Time": {
"S": "4PM-9PM"
},
"Deal": {
"S": "$2 Drafts; $3 Food Menu"
},
"Day": {
"S": "Wednesday"
}
}
}, {
"M": {
"Time": {
"S": "4PM-9PM"
},
"Deal": {
"S": "$2 Beers, House Liquor, Flavored Vodka; 1/2 Price Wings; $5 Pizzas or Pasta Bowl"
},
"Day": {
"S": "Thursday"
}
}
}, {
"M": {
"Time": {
"S": "4PM-9PM"
},
"Deal": {
"S": "$5 Red Bull House Liquor Cocktails; $5 Wings, Nachos, Sliders, Flatbreads; $5 Finlandia Cocktails and Martinis; $15 Sam Adams Light Buckets"
},
"Day": {
"S": "Friday"
}
}
}, {
"M": {
"Time": {
"S": "None"
},
"Deal": {
"S": "None"
},
"Day": {
"S": "Sunday"
}
}
}]
},
"phone": {
"S": "(703) 527-1600"
},
"location": {
"S": "3100 Clarendon Blvd, Arlington, VA 22201"
},
"name": {
"S": "Mister Days"
}
}
Whenever I run this it seems that it populates the barid, phone and location field but leaves the happyhour array blank. Below is what I got in the logs after running the test.
"TableName": "bars",
"Item": {
"barid": {
"S": "{S=005}"
},
"phone": {
"S": "{S=(703) 527-1576}"
},
"location": {
"S": "{S=2500 Hess Road}"
},
"happyhour": {
"L": [
{
"M": {
"Time": {
"S": ""
},
"Deal": {
"S": ""
},
"Day": {
"S": ""
}
}
},
{
"M": {
"Time": {
"S": ""
},
"Deal": {
"S": ""
},
"Day": {
"S": ""
}
}
},
{
"M": {
"Time": {
"S": ""
},
"Deal": {
"S": ""
},
"Day": {
"S": ""
}
[TRUNCATED]
Thu Jun 30 15:36:27 UTC 2016 : Endpoint response body before transformations: {"__type":"com.amazon.coral.service#UnknownOperationException"}
Not sure what I'm doing wrong but anything would help. Thanks!
It looks like happyhour contains an object with a single attribute named L which contains an array of object. You'll probably want to loop over the array so that your mapping template will still work regardless of the length of the array. You also need to reference items in the input by their full path, not just their name.
It should look something like this...
#set($inputRoot = $input.path('$'))
{
"TableName": "bars",
"Item": {
"barid": {
"S": "$inputRoot.barid.S"
},
"name": {
"S": "$inputRoot.name.S"
},
"phone": {
"S": "$inputRoot.phone.S"
},
"location": {
"S": "$inputRoot.location.S"
},
"happyhour": {
"L": [
#foreach($elem in $inputRoot.happyhour.L)
{
"M": {
"Time": {
"S": "$elem.M.Time.S"
},
"Deal": {
"S": "$elem.M.Deal.S"
},
"Day": {
"S": "$elem.M.Day.S"
}
}
}#if($foreach.hasNext),#end
#end
]
}
}
Note that the mapping template order and the output order do not have to match the input order. Also, you don't have to keep the exact same structure. You could, for example, remove all of the extra type information and output cleaner json like this...
#set($inputRoot = $input.path('$'))
{
"TableName": "bars",
"Item": {
"barid": "$inputRoot.barid.S",
"name": "$inputRoot.name.S",
"phone": "$inputRoot.phone.S",
"location": "$inputRoot.location.S",
"happyhour": [
#foreach($elem in $inputRoot.happyhour.L)
{
"Time": "$elem.M.Time.S",
"Deal": "$elem.M.Deal.S",
"Day": "$elem.M.Day.S"
}#if($foreach.hasNext),#end
#end
]
}
This might not be right approach if you really want to do the mapping in the API, but you can leave the problem up to aws-sdk.
You can create a simple lambda function between your API and dynamoDB. Using there some of the methods provided by Aws:
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html
I tackled a similar issue with this function:
var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();
var tableName = "tableName";
var saveData = function (data) {
var params = {
TableName: tableName,
Item: data
};
docClient.put(params, function (err, data) {
if (err) {
console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Added item:", JSON.stringify(data, null, 2));
}
});
};
exports.handler = function (event) {
saveData(event);
};

Resources