DynamoDB putitem in NodeJs - arrays of objects - node.js

I'm trying to set up a small api from AWS Lambda to DynamoDB and I am having trouble figuring out if and how I can write an array of objects into a key.
I have an object like
{
"teamName": "Team Awesome",
"members": [
{
"email": "person-1#example.com",
"name": "Bob"
},
{
"email": "person-2#example.com",
"name": "Alice"
}
]
}
The members array is giving me issues, in the docs it looks like it can be done considering the list types, but there is just no example how HOW to do it, and I am running out of ways to try it.
So is it possible to write something in this format at all and how do you in that case do it?
Example code - what do I put at ???
var AWS = require('aws-sdk');
var dynamodb = new AWS.DynamoDB();
exports.handler = function(event, context) {
var tableName = "GDCCompetition";
var datetime = new Date().getTime().toString();
DynamoDB.putItem({
"TableName": tableName,
"Item": {
"datetime": {
"N": datetime
},
"teamName": {
"S": event.teamName
},
"members": ???
}
});
}

The documentation is not really obvious, but there is a thing called DocClient, you can pass a usual JS object to it and it will do all the parsing and transformation into AWS object (with all the types). You can use it like this:
var AWS = require("aws-sdk");
var DynamoDB = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "MyTable",
Item: {
"teamName": "Team Awesome",
"members": [
{
"email": "person-1#example.com",
"name": "Bob"
},
{
"email": "person-2#example.com",
"name": "Alice"
}
]
}
};
DynamoDB.put(params, function (err) {
if (err) {
return throw err;
}
//this is put
});

You could convert the object to DynamoDb record first
const AWS = require('aws-sdk');
var tableName = "GDCCompetition";
var datetime = new Date().getTime().toString();
const members = [
{
"email": "person-1#example.com",
"name": "Bob"
},
{
"email": "person-2#example.com",
"name": "Alice"
}
];
const marshalled = AWS.DynamoDB.Converter.marshall({ members });
const params = {
"TableName": tableName,
"Item": {
"datetime": {
"N": datetime
},
"teamName": {
"S": event.teamName
},
"members": marshalled.members,
},
}
AWS.DynamoDB.putItem(params, function (err) {
if (err) {
return throw err;
}
});

Related

Find index of object in list in DynamoDB using Lambda

I am trying to use a Lambda script to find the index of an object in a list. As an example, I would like to pass in "userid": "041c9004" and "author": "J.K Rowling" and return index=1 from the books list. If the object does not exist within the books list, return index=-1. We can assume that there will be no duplicate entries.
The structure of the DynamoDB table looks like this. Userid is the primary key.
{
"books": [
{
"author": "J.R.R. Tolkien",
"title": "Lord of the Rings"
},
{
"author": "J.K Rowling",
"title": "Harry Potter"
},
{
"author": "George RR Martin",
"title": "A Song of Ice and Fire"
}
],
"isactive": true,
"ispublic": true,
"lastupdated": 1597690265,
"userid": "041c9004"
}
Here is what I have written of the Lambda function. It is returning index=-1.
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region: 'us-east-1'});
exports.handler = function(event, context, callback){
var params = {
TableName: 'Users',
Key: {
userid: event.userid
}
};
docClient.get(params, function(err, data){
if(err) {
callback(err,null);
} else {
callback(null, data);
//trying to populate this variable with the correct index
var indexOfAuthor = data.Item.books.indexOf(event.author);
console.log('The index of the author is ' + indexOfAuthor);
}
});
};
Assuming event.author is just the author name, you could try:
data.Item.books.findIndex(i => i.author === event.author)

How to remove an object from a list in DynamoDB using Lambda

I'm trying to write a Lambda function to remove an object from a list in DynamoDB. In this case I am passing in "author": "J.K. Rowling", "title": "Harry Potter", and "userid": "041c9004" as parameters. I want to delete the matching object from the books list. What is the correct syntax for the UpdateExpression statement? There may be some other errors within params{} as well.
The DynamoDB table looks like this. userid is the primary key:
{
"books": [
{
"author": "J.R.R. Tolkien",
"title": "Lord of the Rings"
},
{
"author": "J.K Rowling",
"title": "Harry Potter"
},
{
"author": "George RR Martin",
"title": "A Song of Ice and Fire"
}
],
"isactive": true,
"ispublic": true,
"lastupdated": 1597690265,
"userid": "041c9004"
}
Here is the Lambda function:
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region: 'us-east-1'});
exports.handler = function(event, context, callback){
let params = {
ExpressionAttributeValues: {
":attrValue": [{
"author": event.author,
"title": event.title
}]
},
ExpressionAttributeNames : {
"#books" : "books"
},
Key: {
userid: event.userid
},
TableName: 'Users',
UpdateExpression: "REMOVE #books[:attrValue]", //this is incorrect
ReturnValues:"ALL_NEW",
};
docClient.update(params, function(err,data){
if(err) {
callback(err, null)
}else{
callback(null, data)
}
});
}
This is a great question!
Unfortunately, the UpdateExpression will only allow you to REMOVE from the list if you specify an index (docs here).
You'll need to read the item from the DB, find the indexes you want to remove, and REMOVE that specific index.
In case anyone is wondering, here is the full solution:
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region: 'us-east-1'});
exports.handler = function(event, context, callback){
var params = {
TableName: 'Users',
Key: {
userid: event.userid
}
};
docClient.get(params, function(err, data){
if(err) {
callback(err,null);
} else {
var indexOfAuthor = data.Item.books.findIndex(i => i.author === event.author);
console.log('The index of the author is ' + indexOfAuthor);
var updateExpressionString = "REMOVE #books[" + indexOfAuthor + "]"
let paramsdelete = {
ExpressionAttributeNames : {
"#books" : "books"
},
Key: {
userid: event.userid
},
TableName: 'Users',
UpdateExpression: updateExpressionString,
ReturnValues:"ALL_NEW",
};
docClient.update(paramsdelete, function(err,data){
if(err) {
callback(err, null);
}else{
callback(null, data);
}
});
}
});
};

Saving string data in Dynamodb with lamda not working

I am simple creating a post api in which sending data to DynamoDb which i working with hardcoded data but dont know why when i am trying to add the event values its not working.
My lambda function
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({region: 'us-east-2', apiVersion: '2012-08-10'});
exports.handler = (event, context, callback) => {
const params = {
Item: {
"QuestionID": {
S: context.awsRequestId
},
"Would": {
S: event.would
},
"Rather": {
S: event.rather
},
"wouldClick": {
N: event.wouldClick
},
"ratherClick": {
N: event.ratherClick
}
},
TableName: "Would-You-Rather"
};
dynamodb.putItem(params, function(err, data) {
if (err) {
console.log(err);
callback(err);
} else {
console.log(data);
callback(null, data);
}
});
};
This is my model use in post method
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "WouldYouRatherModel",
"type": "object",
"properties": {
"would": {"type": "string"},
"rather": {"type": "string"},
"wouldClick": {"type": "integer"},
"ratherClick": {"type": "integer"}
},
"required": ["would", "rather", "wouldClick", "ratherClick"]
}
My integration request mapping
#set($inputRoot = $input.path('$'))
{
"would" : "$inputRoot.would",
"rather" : "$inputRoot.rather",
"wouldClick" : "$inputRoot.wouldClick",
"ratherClick" : "$inputRoot.ratherClick"
}
If i hardcoded the values in lamda function and test in lamda its saving the values in database this is how i am hardcoding values
"QuestionID": {
S: context.awsRequestId
},
"Would": {
S: "helllo"
},
"Rather": {
S: "bye"
},
"wouldClick": {
N: 1
},
"ratherClick": {
N: 2
}
But problem is when I add the event values in lambda function and try to test the post API from resources it's showing this error
"errorMessage": "There were 2 validation errors:\n* InvalidParameterType: Expected params.Item['wouldClick'].N to be a string\n* InvalidParameterType: Expected params.Item['ratherClick'].N to be a string"
I think the issue is in I am passing the string value in the wrong way? because if there is something wrong in lamda or module then the hardcoded values will also not save in DynamoDB its causing error when I send the values.
Even though wouldClick and ratherClick are Number types (N), they need to be passed to DynamoDB as strings. That is what the error message is telling you.
The documentation on DynamoDB attribute values says:
Numbers are sent across the network to DynamoDB as strings, to maximize compatibility across languages and libraries. However, DynamoDB treats them as number type attributes for mathematical operations.
The Number variables should be formatted as follows:
"wouldClick": { "N": "1" },
"ratherClick": { "N": "2" }

How to make child array pagination with node js and aws dynamo db

I want to make pagination of "car_types" using aws dynamo db and node js. I don't want to use js, Can we make it using dynamo db ? I want total items, total page, page size, current page and data in response.
{
"uid": "222-3333",
"car_types": [
{
"description": "fsdf",
"title": "sdfsd"
},
{
"description": "fdfdfdf",
"title": "dfdfd"
},
{
"description": "dasda",
"title": "asdas"
},
{
"description": "dasd",
"title": "asdas"
},
{
"description": "dasdasd",
"title": "asdas"
}
]
}
Aws Dynamo DB and Node js Code, Which I used to get result.
export function get_car_types_list(){
var params = {
TableName : "cms_cars",
KeyConditionExpression: "#uid = :uid",
ExpressionAttributeNames:{
"#uid": "uid"
},
ExpressionAttributeValues: {
":uid": "222-3333"
}
};
return docClient.query(params).promise()
.then(function(data) {
console.log(data);
return data;
}).catch( (err) => {
console.log('got Error', err);
});
}
I want Result using dynamo db query:
{
"totalItem":5,
"totalPage":1,
"pageSize":"1",
"currentPage":"1",
"car_types": [
{
"description": "fsdf",
"title": "sdfsd"
},
{
"description": "fdfdfdf",
"title": "dfdfd"
},
{
"description": "dasda",
"title": "asdas"
},
{
"description": "dasd",
"title": "asdas"
},
{
"description": "dasdasd",
"title": "asdas"
}
]
}
DynamoDb will return 1 mb data when scan/query is executed, also LastEvaluatedKey is added to result if there are any remaining data. If you pass ExclusiveStartKey: LastEvaluatedKey you can scan/query with pagination. I added some tweaks to your approach, it may help you.
Edit: You can limit the result by passing Limit: Number to your params. This will allow you to limit the returning item count and you can get more with LastEvaluatedKey.
export function get_car_types_list(LastEvaluatedKey){
var params = {
TableName : "cms_cars",
KeyConditionExpression: "#uid = :uid",
ExpressionAttributeNames:{
"#uid": "uid"
},
ExpressionAttributeValues: {
":uid": "222-3333"
},
Limit: 5,
};
if (LastEvaluatedKey) {
params.ExclusiveStartKey = LastEvaluatedKey;
}
return docClient.query(params).promise()
.then(function(data) {
console.log(data);
return data;
}).catch( (err) => {
console.log('got Error', err);
});
}

How to put an array of object inside DynamodDB using nodejs

I have a JSON having an array of objects in the following format. How can i add it in dynamoDB using a lambda function(NodeJS). Assume my JSON is in an s3 bucket name "databucket" and the file name is data.json. I have used "userId" as the key while creating the DB table. Thanks in advance
{
"records": [
{
"first-name": "Mark",
"last-name": "rob",
"userId": "fvdvfd"
},
{
"first-name": "Alan",
"last-name": "thomas",
"userId": "wee"
},
{
"first-name": "Joan",
"last-name": "Young",
"userId": "wee"
}
]
}
First, you have to retrieve the data.json from S3 bucket and read it's content into a variable.
Secondly, you should create dynamodb parameter to provide to the dynamodb client PUT method. Since it is an array of objects you have to loop through the array and put each object or else you can use batchWrite method in dynamodb as follows,
var AWS = require('aws-sdk');
var insertBatchRecords = function(callback) {
var dynamodb = new AWS.DynamoDB();
var bulkInsertParams = {
RequestItems: {
"Records": [
{
PutRequest: {
Item: {
"first-name": "Mark",
"last-name": "rob",
"userId": "fvdvfd"
}
}},
{
PutRequest: {
Item: {
"first-name": "Alan",
"last-name": "thomas",
"userId": "wee"
}
}}]
}
};
dynamodb.batchWriteItem(bulkInsertParams, callback);
}

Resources