How to remove a nested attribute from dynamodb table? - node.js

How to remove a nest attribute from dynamodb table on the basis of id? I m using nodejs(Typescript) with local dynamodb.
// check if post exists
const post = await dynamo.get({
TableName: "PostTable",
Key: { id: event.body.postId }
}).promise();
if (!post.Item) {
return formatJSONResponse({
message: `no post with this id`,
statuscode: 404
});
}
const params = {
TableName: "PostTable",
Key: { id: event.body.postId },
UpdateExpression:
"REMOVE comments.#id",
ExpressionAttributeValues: {
"#id": event.body.id
},
ReturnValues : "UPDATED_NEW"
}
let res= await dynamo.update(params).promise();
return formatJSONResponse({
message: `Comment has been removed
event,
result: res
});
dynamobdb table picture

Related

How to update Elasticsearch dynamic data multiple fields using UpdateByQuery in NodeJS

How to update Elasticsearch data multiple fields using UpdateByQuery in NodeJS ?
Note - My data is coming dynamically. I can't pass static value. I have to pass like - data.name, data.id
Code -
function updateInELK(data) { // Update by Id
const updateScript = {
inline: {
"ctx._source.name = "+data.name,
"ctx._source.role = "+data.role,
};
return new Promise((resolve, reject) => {
elasticsearch.updateByQuery({
index: indexName,
body: {
query: { match: { id: data.id } },
script: updateScript,
lang: 'painless',
}
}).then((response) => {
resolve(response);
}).catch((err) => {
console.log(err);
reject("Elasticsearch ERROR - data not updated")
})
});
}
Error -
TypeError: "ctx._source.name = " is not a function
Please let me know, if any other options are there. I can't update using id, because I don't know the id. I wanted to use updateByQuery, with conditions in the query parameters.
Here are the solutions -
await esClient.updateByQuery({
index: "data",
type: "doc",
refresh: true,
body:{
query:{
match: {
dataId: "70897e86-9d69-4700-b70e-881a7f74e9f9"
}
},
script:{
lang:"painless",
source:`ctx._source.data='This is updated test data';ctx._source.updatedAt=params.date;ctx._source.segmentId=params.segmentId`,
params:{
date: Date.now(),
segmentId: null
}
}
}
});

How to patch for each object in an array in Lambda and Dynamodb with NodeJS

How do i add 200 to "money" in every object in my array in a lambda function with Nodejs?
JSON formatted DynamoDB table:
[{name: "Player1", money: 100},{name: "Player2", money: 50},{name: "Player3", money: 200}]
This is my lambda function updating Player1's money, but how do i loop through the rest, without having to do 3 api calls?
async function updateMoney(player) {
const params = {
TableName: dynamodbTableName,
Key: {
'name': player
},
UpdateExpression: "set money = money + :amount",
ExpressionAttributeValues: {
':amount': 300
},
ReturnValues: 'UPDATED_NEW'
}
return await dynamodb.update(params).promise().then((response) => {
const body = {
Operation: "UPDATE",
Message: "SUCCESS",
Item: response
}
return util.buildResponse(200, body);
}, (error) => {
return util.buildResponse(200, error);
});
}

Using React, NodeJS, and Postgres: Having trouble being able to delete and updating todos

I am creating simple todo app with postgre and react.
The server side the delete and update are defined as below.
app.put("/todos/:id", async (req, res) => {
try {
const { id } = req.params;
const { description } = req.body;
const updateTodo = await pool.query(
"update todo set description = $1 where todo_id = $2",
[description, id]
);
res.json("todo updated !!");
} catch (error) {
console.error(error.message);
}
});
// delete todo
app.delete("/todos/:id", async (req, res) => {
try {
const { id } = req.params;
const deleteTodo = await pool.query("delete from todo where todo_id = $1", [
id,
]);
res.json("todo deleted !!");
} catch (error) {
console.error(error.message);
}
});
On the front end (React) this is how I am calling the update and delete
const updateDescription = async () => {
try {
handleClose();
const body = { description };
const response = fetch(`http://localhost:3000/${todo.todo_id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
console.log(response);
} catch (error) {
console.log(error.message);
}
};
Delete todo is in the other component.
const deleteTodo = async (id) => {
try {
const deleteTodo = await fetch(`http://localhost:3000/${id}`, {
method: "DELETE ",
});
console.log(deleteTodo);
setTodods(todos.filter((todo) => todo.todo_id !== id));
} catch (error) {
console.log(error.message);
}
};
So when I am doing delete or put request its not updating it in the DB.
On the browser console I am getting this error.
Failed to execute 'fetch' on 'Window': 'DELETE ' is not a valid HTTP method.
Edited
Response {type: "cors", url: "http://localhost:3000/3", redirected: false, status: 404, ok: false, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 404
statusText: "Not Found"
type: "cors"
url: "http://localhost:3000/3"
__proto__: Response
For insert todo its working but for delete and put request its not updating in the database.
So can somebody tell me whats going wrong here ?
There is a space after DELETE, correct it should work properly. Even if its a simple todo App, its always good practice to create an enum or const when we are dealing with fixed string, i.e., we know the string would not change so that we can have consistency and skip over these kind of issues.
const METHOD = {
GET: "GET",
PUT: "PUT",
POST: "POST",
DELETE: "DELETE"
};

ValidationException in lambda API

I have the following code:
function updateComplaint(complaints) {
return API.put("kleen", `/Complaint/${state.complaint[0].id}`, {
body: state.complaint[0]
});
}
but when ever I run it, I get the following error:
This is the table I am trying to edit:
What am I doing wrong and what should my code look like?
Code for my API:
import * as dynamoDbLib from "./libs/dynamodb-lib";
import { success, failure } from "./libs/response-lib";
export async function main(event, context) {
const data = JSON.parse(event.body);
const params = {
TableName: process.env.tableName,
// 'Key' defines the partition key and sort key of the item to be updated
// - 'userId': Identity Pool identity id of the authenticated user
// - 'noteId': path parameter
Key: {
typeName: event.requestContext.identity.typeName,
id: event.pathParameters.cognitoIdentityId
},
// 'UpdateExpression' defines the attributes to be updated
// 'ExpressionAttributeValues' defines the value in the update expression
UpdateExpression: "SET adminComment = :adminComment, updatedAt = :updatedAt",
ExpressionAttributeValues: {
":updatedAt": Date.now() || null,
":adminComment": data.adminComment || null
},
// 'ReturnValues' specifies if and how to return the item's attributes,
// where ALL_NEW returns all attributes of the item after the update; you
// can inspect 'result' below to see how it works with different settings
ReturnValues: "ALL_NEW"
};
try {
await dynamoDbLib.call("update", params);
return success({ status: true });
} catch (e) {
console.log(e);
return failure({ status: false });
}
}

AWS Lambda Node Js - Increment value if exist else add element

I want increment value if exist else add element.
+-----------------------+
| id | iteration | data |
+-----------------------+
| 10 | 1 | foo1 |
| 11 | 1 | foo2 |
| 12 | 2 | foo3 |
+-----------------------+
my code:
var AWS = require('aws-sdk');
var documentClient = new AWS.DynamoDB.DocumentClient({'region': 'eu-west-1'});
exports.handler = function(event, context, callback) {
var params = {
Item: {
id: uuid,
iteration: 1,
data: body.data
},
TableName: "my-table"
};
documentClient.put(params, function(err, data) {
if (err) {
console.log("Error", err);
const errResponse = {
statusCode: 500,
headers: {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify({ Error: 500, device : "DynamoDB", detail : err })
};
callback(null, errResponse);
} else {
console.log("Success", params.Items);
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify("thanks")
};
callback(null, response);
}
});
}
My insert is OK.
I try with:
var params = {
TableName: "my-table",
Key:{
"id": uuid
},
UpdateExpression: "set iteration = iteration + :val",
ExpressionAttributeValues:{
":val": 1
},
ReturnValues:"UPDATED_NEW"
};
documentClient.update(params, function(err, data) {
if (err) {
console.error("Unable to update item. Error JSON:", JSON.stringify(err, null, 2));
const errResponse = {
statusCode: 500,
headers: {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify({ Error: 500, device : "DynamoDB", detail : err })
};
callback(null, errResponse);
} else {
console.log("UpdateItem succeeded:", JSON.stringify(data, null, 2));
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify("thanks")
};
callback(null, response);
}
});
Update is OK (increment -> 2)
But I want increment value ONLY if exist else ONLY add element. Both methods are asynchronous, how should I do?
Your 2nd answer is close. In your UpdateExpression you need both and ADD and a SET on the same line. like the following:
UpdateExpression: "ADD iteration :iteration SET itemdata = :itemdata",
This is formally documented in the AWS DOCS for UpdateItem under DynamoDB
scrolling down it says
ADD - Adds the specified value to the item, if the attribute does not
already exist. If the attribute does exist, then the behavior of ADD
depends on the data type of the attribute:
If the existing attribute is a number, and if Value is also a number,
then Value is mathematically added to the existing attribute. If Value
is a negative number, then it is subtracted from the existing
attribute.
I was able to find a AWS forum post that had a successful upsert, as well as another SO answer with the ADD and SET syntax in the same line. Below is some code that will run if placed in a new lambda (change your region to match where your table is)
var AWS = require('aws-sdk');
var documentClient = new AWS.DynamoDB.DocumentClient({'region': 'eu-central-1'});
exports.handler = function(item, context, callback) {
var params = {
TableName: "my-table",
Key:{
"id": item.id
},
UpdateExpression: "ADD iteration :iteration SET itemdata = :itemdata",
ExpressionAttributeValues:{
':iteration': 1,
':itemdata' : item.data
},
ReturnValues:"NONE"
};
documentClient.update(params, function(err, data) {
if (err) {
console.log("Error", err);
const errResponse = {
statusCode: 500,
headers: {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify({ Error: 500, device : "DynamoDB", detail : err })
};
callback(null, errResponse);
} else {
console.log("Success", params.Items);
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify("upsert complete.")
};
callback(null, response);
}
});
};
note: data is a reserved keyword, and I got the following error:
Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: data
consider changing it to something else. I used itemdata.
Running it once will insert a new record. The following images are before and after images of the table after I run the lambda the second time.

Resources