API Gateway and DynamoDB PutItem for String Set - amazon-dynamodb

I can't seem to find how to correctly call PutItem for a StringSet in DynamoDB through API Gateway. If I call it like I would for a List of Maps, then I get objects returned. Example data is below.
{
"eventId": "Lorem",
"eventName": "Lorem",
"companies": [
{
"companyId": "Lorem",
"companyName": "Lorem"
}
],
"eventTags": [
"Lorem",
"Lorem"
]
}
And my example template call for companies:
"companies" : {
"L": [
#foreach($elem in $inputRoot.companies) {
"M": {
"companyId": {
"S": "$elem.companyId"
},
"companyName": {
"S": "$elem.companyName"
}
}
} #if($foreach.hasNext),#end
#end
]
}
I've tried to call it with String Set listed, but it errors out still and tells me that "Start of structure or map found where not expected" or that serialization failed.
"eventTags" : {
"SS": [
#foreach($elem in $inputRoot.eventTags) {
"S":"$elem"
} #if($foreach.hasNext),#end
#end
]
}
What is the proper way to call PutItem for converting an array of strings to a String Set?

If you are using JavaScript AWS SDK, you can use document client API (docClient.createSet) to store the SET data type.
docClient.createSet - converts the array into SET data type
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
TableName:table,
Item:{
"yearkey": year,
"title": title
"product" : docClient.createSet(['milk','veg'])
}
};

Related

Appsync 'Batch Create' Resolver gives "mapping template" error

I'm trying to create a resolver for a BatchCreateIngredients mutation I created, but when I run the mutation I'm getting an error of type MappingTemplate and I'm not sure why.
My table's name is IngredientsTable and I'm not using any cognito verification.
The mutation:
mutation batchCreateIngredient {
batchCreateIngredients(
input: [
{name: "Cookie" vegan: VEGAN glutenfree: GLUTENFREE},
{name: "Pizza", vegan: VEGAN, glutenfree: GLUTENFREE},
]) {
items{
id
name
vegan
}
}
}
The error message:
{
"data": {
"batchCreateIngredients": null
},
"errors": [
{
"path": [
"batchCreateIngredients"
],
"data": null,
"errorType": "MappingTemplate",
"errorInfo": null,
"locations": [
{
"line": 6,
"column": 3,
"sourceName": null
}
],
"message": "Item list elements can't be null for table 'IngredientTable' at path '$[tables]'"
}
]
}
The Relevant Parts of My Schema:
input CreateIngredientInput {
name: String!
vegan: Vegan!
glutenfree: GlutenFree!
popularity: Int
}
enum GlutenFree {
GLUTENFREE
CONTAINS_GLUTEN
UNKNOWN
}
type Ingredient {
name: String!
id: ID!
vegan: Vegan
glutenfree: GlutenFree
popularity: Int
}
type IngredientConnection {
items: [Ingredient]
nextToken: String
}
type Mutation {
createIngredient(input: CreateIngredientInput!): Ingredient
batchCreateIngredients(input: [CreateIngredientInput]): IngredientConnection
updateIngredient(input: UpdateIngredientInput!): Ingredient
deleteIngredient(input: DeleteIngredientInput!): Ingredient
}
enum Vegan {
VEGAN
NON_VEGAN
UNKNOWN
}
The Resolver for BatchCreateIngredients:
#set($ingdata = [])
#foreach($ing in ${ctx.args.input})
$util.qr($ingdata.add($util.dynamodb.toMapValues($item)))
#end
{
"version" : "2018-05-29",
"operation" : "BatchPutItem",
"tables" : {
"IngredientTable": $utils.toJson($ingdata)
}
}
From what I can tell, it looks like the issue is in the request mapping template. You have called the loop variable $ing, but you are passing "$item" to the toMapValues function. Can you try changing "item" to "ing" ?
And also you are passing
{name: "Cookie" vegan: VEGAN glutenfree: GLUTENFREE}
but mapping
items{
id
name
vegan
}
glutenfree is missing and id is not handled in the resolver

Querying Cosmos Nested JSON documents

I would like to turn this resultset
[
{
"Document": {
"JsonData": "{\"key\":\"value1\"}"
}
},
{
"Document": {
"JsonData": "{\"key\":\"value2\"}"
}
}
]
into this
[
{
"key": "value1"
},
{
"key": "value2"
}
]
I can get close by using a query like
select value c.Document.JsonData from c
however, I end up with
[
"{\"key\":\"value1\"}",
"{\"key\":\"value2\"}"
]
How can I cast each value to an individual JSON fragment using the SQL API?
As David Makogon said above, we need to transform such data within our app. We can do as below:
string data = "[{\"key\":\"value1\"},{\"key\":\"value2\"}]";
List<Object> t = JsonConvert.DeserializeObject<List<Object>>(data);
string jsonData = JsonConvert.SerializeObject(t);
Screenshot of result:

Task timed out after 3.00 seconds - Lambda application with nodeJS

I am trying to put a hard-coded data item to DynamoDB. I am using AWS SDK object to perform this update. And all the debug "Console.log" in the below code is getting printed but eventually it prints Task timed out after 3.00 seconds
With no update to the DynamoDB
function updatedb(intent, session, callback) {
let country;
const repromptText = null;
const sessionAttributes = {};
let shouldEndSession = false;
console.log("In the function");
const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient({ region: 'eu-west-1' });
var params = {
TableName: "Location",
Item: {
"LocationID": { "S": "11" },
"Country": { "S": "10" },
"Description": { "S": "10" },
"Name": { "S": "10" }
}
};
console.log("Param loaded & executing the DocClient Put");
docClient.put(params, function (err, data) {
if (err) {
speechOutput = 'Update failed';
console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
callback(sessionAttributes,
buildSpeechletResponse(intent.name, speechOutput, repromptText, shouldEndSession));
} else {
console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
speechOutput = 'Update successful';
callback(sessionAttributes,
buildSpeechletResponse(intent.name, speechOutput, repromptText, shouldEndSession));
}
});
}
The following items are already checked
1) There is a table named "Location" in DynamoDB
2) Both DynamoDB and this lambda function are in ue-west-1 (Ireland)
3) The role assigned for this Lambda function can do all operation on this table. See the policy details below
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1510603004000",
"Effect": "Allow",
"Action": [
"dynamodb:*"
],
"Resource": [
"arn:aws:dynamodb:eu-west-1:752546663632:table/Location"
]
}
]
}
How does my Lambda function locate the table "location" just with the region?- the code does not appear to have end-point, etc.? - just developed based on a tutorial.
Is that what I am missing?
Please can you help?
I had a similar issue, try putting require statements in the beginning of your function.
const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient({ region: 'eu-west-1' });
I believe that AWS locates the table based on your identity, in combination with the region and the table name.
I was able to successfully post to a table using this code:
const AWS = require('aws-sdk');
const dynamoDB = new AWS.DynamoDB({region: 'us-west-2'});
var params = {
TableName: "my-table",
Item: {
"LocationID": { S: "11" },
"Country": { S: "10" },
"Description": { S: "10" },
"Name": { S: "10" }
}
};
dynamoDB.putItem(params, (err, data) => {
if (err){
console.error(err.stack);
} else {
console.log(data);
}
});
If you can in fact post to the table from the CLI, then there is still at least one remaining issue: it appears that you are using the DocumentClient class incorrectly. It looks like you're mixing up the syntax for DynamoDB.putItem with the syntax for DynamoDB.DocumentClient.put.
If you notice, my code uses the DynamoDB class directly-- based on what you're doing, I see no reason why you couldn't do the same. Otherwise, you should change your Item object:
var params = {
TableName: "my-table",
Item: {
"LocationID": "11",
"Country": "10",
"Description": "10",
"Name": "10"
}
};
My guess is your code is currently erroring out because you are trying to insert Maps where you want to insert Strings. If you have Cloudwatch configured you could check the logs.
Finally, I don't see you using callback in your code. If your intention is to respond to a client calling the lambda you should do that. Depending on your NodeJS version, the lambda can simply time out without returning a useful response.

How can I verify that a map's values are not empty

Suppose I have a contract like this specified in groovy:
org.springframework.cloud.contract.spec.Contract.make {
request {
method "GET"
url "/api/profiles"
headers {
header('Accept': 'application/json;charset=UTF-8')
header('Content-Type': 'application/json;charset=UTF-8')
}
}
response {
status 200
headers {
header('Content-Type': 'application/json;charset=UTF-8')
}
body(
value(
stub(
'''\
[
{
"profile": "profile1",
"myMap": {}
},
{
"profile": "profile2",
"myMap": {
"12345": "FOO",
"asdf": "BAR"
}
}
]
'''
),
test(
[
[
"profile" : regex(nonEmpty()),
"myMap": [
[
??
]
]
]
]
)
)
)
}
}
Now I want to test that the map contains String to String entries where the values must not be empty. The map itself may be empty.
How can I test for dynamic key name?
On the response side of the contract you have to chose whether you're using the map notation or the string notation. If you want to do assertions on pieces of the response you have to embed those assertions inside the body or use the test matchers.
You can put the body as a multiline string and then write the testMatchers section
testMatchers{
jsonPath('$.[*].myMap', byCommand('assertKeys($it)'))
}
then it's enough for you to provide the assertion in the assertKeys method.

DyanamoDB SCAN with nested attribute

Can I scan DynamoDB by 'order.shortCode', in the given example. The console is indicating I can't with dot notation, and I can't find any documentation on it.
{
"key2": "cj11b1ygp0000jcgubpe5mso3",
"order": {
"amount": 74.22,
"dateCreated": "2017-04-02T19:15:33-04:00",
"orderNumber": "cj11b1ygp0000jcgubpe5mso3",
"shortCode": "SJLLDE"
},
"skey2": "SJLLDE"
}
To scan by a nested attribute, you should use ExpressionAttributeNames parameter to pass each path component (i.e. order and shortCode) separately into FilterExpression like shown below:
var params = {
TableName: 'YOUR_TABLE_NAME',
FilterExpression: "#order.#shortCode = :shortCodeValue",
ExpressionAttributeNames: {
'#order': 'order',
"#shortCode": "shortCode"
},
ExpressionAttributeValues: {
':shortCodeValue': 'SJLLDE'
}
};
dynamodbDoc.scan(params, function(err, data) {
});
Here is a link to documentation explaining this:
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ExpressionAttributeNames.html#Expressions.ExpressionAttributeNames.NestedAttributes

Resources