DynamoDB - Update or Create if not found method - javascript

In DynamoDB, how can I make an update or create if not found method if I have a hash key and a range key in my table. Below works if I have a table with only a hash key, but not for tables with a hash and range key:
var save = function(user_id, store_id, callback){
var DOC = require('dynamodb-doc'),
docClient = new DOC.DynamoDB();
var params = {
TableName: 'stores',
ReturnValues: 'NONE',
Key: {
'user_id': user_id
},
ConditionExpression: "#a = :store_id_val",
UpdateExpression: 'SET #a = :store_id_val',
ExpressionAttributeNames: {
'#a': 'store_id'
},
ExpressionAttributeValues: {
':store_id_val': store_id
}
};
// Save DynamoDB Document
docClient.updateItem(params, function(error, response) {
return callback(error, response);
});
}

It is simple. I just need to specify both hash and range key in the Key parameter. Then I can get away with this:
var save = function(user_id, store_id, callback) {
var DOC = require('dynamodb-doc'),
docClient = new DOC.DynamoDB();
var params = {
TableName: 'stores',
ReturnValues: 'NONE',
Key: {
'user_id': user_id,
'store_id': store_id
}
};
// Save DynamoDB Document
docClient.updateItem(params, function(error, response) {
return callback(error, response);
});
}

Related

GetItem by date in DynamoDB results in ValidationException

I need a data filtered by date but I am getting an error
Error ValidationException: The provided key element does not match the schema
My table has a primary key (only partition key) of id.
async function fetchDatafromDatabase() { // get method fetch data from dynamodb
var date = todayDate();
var params = {
TableName: table,
Key: {
"date": date
}
};
let queryExecute = new Promise((res, rej) => {
dynamoDB.get(params, function (err, data) {
if (err) {
console.log("Error", err);
rej(err);
} else {
console.log("Success! get method fetch data from dynamodb");
res(JSON.stringify(data, null, 2));
}
});
});
const result = await queryExecute;
console.log(result);
}
For getting an item from DynamoDB, we must pass primary key, in this case, its just partition key 'id' (assuming it is numeric and storing epoc date)
var documentClient = new AWS.DynamoDB.DocumentClient();
var date = Date.now();
console.log("date", date);
var params = {
TableName: "test2",
Key: {
id: date,
},
};
documentClient.get(params, function (err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data);
}
});
Complete Example to put an item and get it.
var documentClient = new AWS.DynamoDB.DocumentClient();
var date = Date.now();
documentClient.put(
{
TableName: "test2",
Key: {
id: date,
},
},
function (err, data) {
if (err) console.log("err", err);
if (data) {
documentClient.get(
{
TableName: "test2",
Key: {
id: date,
},
},
function (errGet, dataGet) {
if (errGet) {
console.log("Error", errGet);
} else {
console.log("Success", dataGet);
}
}
);
}
}
);

AWS Dynamodb not fetching data synchronously by node js

I am new on node js dynamo db I wrote a node js sdk to fetch one row from a table ona dynamodb. It is fetching data correctly but not immediately for this I got error
My code is below a simple code
var AWS = require("aws-sdk");
var config = function(){
AWS.config.update({region: 'us-east-1'});
// Create the DynamoDB service object
var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
var params = {
TableName: 'tblConfigs',
// Key: {
// "id" : {S: "1"},
// }
ExpressionAttributeValues: {
":v1": {
S: "1"
}
},
FilterExpression: "id = :v1",
};
var v;
var json = ddb.scan(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
v = data;
// console.log(JSON.stringify(data.Item));
// return JSON.stringify(data.Item);
}
});
// if(v=="u")
// for(var i=0;)
v = v.Items[0];
// for()
var con = {
"host": v.endpoint.S,
"user": v.endpoint.username.S,
"password": v.endpoint.password.S,
"database": v.endpoint.database_name.S
};
return con;
}
And I got the below error
> config()
TypeError: Cannot read property 'Items' of undefined
at config (repl:31:7)
as v is undefined so it is giving the error but v is not undefined when I execute the code in node console it first time gave undefined next time it gave value
like below
> v
{ Items:
[ { password: [Object],
stage: [Object],
username: [Object],
id: [Object],
endpoint: [Object],
database_name: [Object] } ],
Count: 1,
ScannedCount: 1 }
how can I fetch the row immediately not after some time? IS there any good way in dynamodb I tried, get, getItem, scan, query all are giving data correctly but not immediately...Please suggest
You are missing one important thing: Javascript execution is asynchronous. As long as you are not using async/await syntax you have to "play" with callbacks like this:
var ddb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
function loadConfig(callback) {
var params = {
TableName: 'tblConfigs',
ExpressionAttributeValues: {
':v1': {
S: '1'
}
},
FilterExpression: 'id = :v1'
};
ddb.scan(params, function (error, data) {
if (error) {
callback(error);
} else {
var item = data.Items[0];
callback(null, {
'host': item.endpoint.S,
'user': item.endpoint.username.S,
'password': item.endpoint.password.S,
'database': item.endpoint.database_name.S
});
}
});
}
loadConfig(function (error, configuration) {
if (error) {
console.log(error);
} else {
// Your connection logic (JUST AN EXAMPLE!)
var connection = mysql.connect({
host: configuration.host,
user: configuration.user,
password: configuration.password,
database: configuration.database
})
}
});
Btw. storing database configurations in DynamoDB isn't a good solution, i would recommend to check AWS Systems Manager Parameter Store.
Edit
To give you a short example how the async/await syntax looks like
var ddb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
const loadConfig = async () => {
const { Items } = await ddb.scan({
TableName: 'tblConfigs',
ExpressionAttributeValues: {
':v1': {
S: '1'
}
},
FilterExpression: 'id = :v1'
}).promise();
const item = Items[0];
return {
'host': item.endpoint.S,
'user': item.endpoint.username.S,
'password': item.endpoint.password.S,
'database': item.endpoint.database_name.S
};
};

DynamoDB Validation Exception - Key element does not match the schema

I'm trying to get an item from my DynamoDB but get the following error
ValidationException: The provided key element does not match the
schema
The create item piece of the code works. But no the Get item.
Table Info:
Table Name: movieTable
Primary Partition Key: itemID
Primary Sort Key: sortKey
Here's the code for the create and update:
var fbUserId;
var params;
var keyText;
var attText;
var valText;
var dynamodb = null;
var docClient = null;
var appId = '405140756489952'; //from facebook
var roleArn = 'arn:aws:iam::042765862882:role/Verzosa'; //from AWS IAM
var resultData = null;
document.getElementById('putThis').onclick = function () {
dynamodb = new AWS.DynamoDB({ region: 'us-west-2' });
docClient = new AWS.DynamoDB.DocumentClient({ service: dynamodb });
keyText = document.getElementById("keyValue").value;
attText = document.getElementById("attributeText").value;
valText = document.getElementById("valueText").value;
console.log("Key Value: ", keyText);
console.log("Attribute: ", attText);
console.log("Value: ", valText);
params = {
TableName: 'movieTable',
Item: {
itemID: keyText,
sortKey: valText
}
};
docClient.put(params, function(err, data){
if (err) console.log(err);
else
{
resultData = data;
console.log(resultData);
}
})
};
document.getElementById('getThis').onclick = function () {
dynamodb = new AWS.DynamoDB({ region: 'us-west-2' });
docClient = new AWS.DynamoDB.DocumentClient({ service: dynamodb });
keyText = document.getElementById("keyValue").value;
attText = document.getElementById("attributeText").value;
console.log("Key Value: ", keyText);
console.log("Attribute: ", attText);
params = {
TableName: 'movieTable',
Key: {
itemID: keyText,
},
ProjectionExpression: "#a",
ExpressionAttributeNames: {
'#a': attText
}
};
docClient.get(params, function (err, data)
{
if (err)
{
console.log(err, err.stack);
}
else
{
console.log("success, logging data: ");
console.log(data);//shows keys
console.log("attribute 1 is " + data.Item.sortKey)
//var output = data.Item.attribute1;
l = document.getElementById("output");
l.innerHTML = data.Item.sortKey;
}
})
};
Any help would be appreciated.
You are getting this error because when using AWS.DynamoDB.DocumentClient.get method, you must specify both hash and sort key of an item. But you have only hash key specified (itemId), and sort key is missing.
Here is how your get params should look like:
...
params = {
TableName: 'movieTable',
Key: {
itemID: keyText,
sortKey: valText // <--- sort key added
},
ProjectionExpression: "#a",
ExpressionAttributeNames: {
'#a': attText
}
};
docClient.get(params, function (err, data) {
...
If you'd like to get a record with a hash key only, without specifying its sort key, you should use query method instead of get:
...
params = {
TableName: 'movieTable',
KeyConditionExpression: '#itemID = :itemID',
ProjectionExpression: "#a",
ExpressionAttributeNames: {
'#a': attText,
'#itemID': 'itemID'
},
ExpressionAttributeValues: {
':itemID': keyText
}
};
dynamodbDoc.query(params, function(err, data) {
...
Be aware that while get method always returns 1 or no records, query can possibly return multiple records, so you would have to revisit your current implementation of get callback (e.g. instead of accessing data.Item you should use data.Items array, see query method docs)
You need to pass both primary key and sort key in the params.
You can find these keys from the table UI.
and you should pass those as parameters when making the request
this.ProjectsModel.delete({pk1:"project#giri-test#appsc", sk1:"metadata#giri-test#appsc"}, (error) => {
if (error) {
console.error(error);
} else {
console.log("Successfully deleted item");
}
});

AWS DynamoDB on Lambda not returning inserted data

const AWS = require('aws-sdk')
const docClient = new AWS.DynamoDB.DocumentClient({ region: 'eu-central-1' })
const createDocument = (text, callback) => {
const createParams = {
Item: {
text: text
},
TableName: 'ToDoItems'
}
docClient.put(createParams, (err, data) => {
if(err) {
callback(err, null)
} else {
callback(null, data)
}
})
}
exports.handle = (event, context, callback) => {
createDocument(event.text, (err, data) => {
if(err) {
callback(err, null)
} else {
callback(null, data)
}
})
}
That's my AWS Lambda function, the issue is that when I get a callback, data object is empty, even though document is inserted into DynamoDB. What could the issue be here?
You can't. You have to separately query. On put, if you set ReturnValues: 'ALL_NEW', then you'll get "ReturnValues can only be ALL_OLD or NONE"
Note the 'possible' in AWS's documentation:
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#put-property
ReturnValues — (String) Possible values include:
"NONE"
"ALL_OLD"
"UPDATED_OLD"
"ALL_NEW"
"UPDATED_NEW"
Also, instead of separately querying, you can also just use the params value. If it was saved, then what you have in createParams.Item is basically what's returned if you were to separately query.
There is a workaround - You can use update method of DynamoDB.DocumentClient.
TableName: "table",
Key: {
id: randomId
},
AttributeUpdates: {
authorId: {Action: "PUT", Value: event.authorId},
date: {Action: "PUT", Value: event.date},
description: {Action: "PUT", Value: event.description},
title: {Action: "PUT", Value: event.title}
},
ReturnValues: "ALL_NEW"
This method will create new item and return all what you need
You have to request the return values, like this:
const createParams = {
Item: {
text: text
},
TableName: 'ToDoItems',
ReturnValues: 'ALL_NEW'
}
This is documented here.
I did have to implementing that the return in .then() was params.Item, like this:
var params = {
TableName:table,
Item:{
"name": value,
"email": value2,
}
};
console.info("Adding a new item...");
await docClient.put(params)
.promise()
.then(data => {
return params.Item;
}).catch(error => {
console.error(error)
throw new Error(error)
})

How to update document field in mongodb?

I am new to Mongodb so below code i am trying to update document field string i have object recieved in post req.body now based on _id i want to update string field but it is not updating record with below implementation. How can i update record using _id ? Any better approach to update record in terms of async will be appreciated.
routes.js
var Diagram = require('./diagram');
router.post('/saveUpdateDiagram',function(req,res){
console.log(req.body._id);
Diagram.update(req.body);
});
diagram.js
var diagram = require('./diagram.model');
var mongoose = require('mongoose');
var Diagram = {
index: function(callback) {
diagram.find({}, function(err, result) {
if (!err) {
callback(result);
}
});
},
update: function(data) {
console.log('data in controller', data);
Diagram.update({ $set: { 'string' : data.string } });
}
}
module.exports = Diagram;
data.json
{
_id: "57fe42efc3590c7686bad563"
groups: Array[0]
owner: "sh587"
string: "test string should be updated"
text: "gcs_wf_dit.bpmn"
users: Array[1]
}
We know that JavaScript is case sensitive language you should use diagram.update not Diagram.update
use `diagram.update({ $set: { 'string' : data.string } });
diagram.js should be
diagram.js
var diagram = require('./diagram.model');
var mongoose = require('mongoose');
var Diagram = {
index: function(callback) {
diagram.find({}, function(err, result) {
if (!err) {
callback(result);
}
});
},
update: function(data) {
console.log('data in controller', data);
diagram.update({_id: data._id}, { $set: { 'string' : data.string } });
}
}
module.exports = Diagram;
Make sure you have "string" field in diagram model. as mongoose allow only those fields which are available in schema. If not then add
string: {type: String}
and then use
var diagram = require('./diagram.model');
var mongoose = require('mongoose');
var Diagram = {
index: function(callback) {
diagram.find({}, function(err, result) {
if (!err) {
callback(result);
}
});
},
update: function(data) {
diagram.update({_id: data._id}, { $set: { 'string' : data.string } });
}
}
module.exports = Diagram;

Categories