I want to push some data from a form to DynamoDB for storage. If I include data for nutrients, this all works swimmingly. When I exclude nutrients, for some reason the push fails.
I want this to work with any of these values missing except recipe_index
and item_type
(recipe_index
is auto-generated from a query at the top of the script; item_type
is manually set to {S: 'recipe'}
).
There is nothing I see to make it work conditional to nutrients's availability. My only clue is a generic log of Error RequestAbortedError: Request aborted
. I have tried to move around and simplify this code in the process to troubleshoot it; to no avail. Googling was no luck either. I usually find something on an error message...
My hope is one of you fine Internet strangers can save me from my own stupidity as I am sure I am overlooking something that should be obvious. I am still pretty new to DynamoDB, JS, and React.
export function SaveCreateButton(props){
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Create DynamoDB service object
var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
// Query for number of items in the table through GSI
var params = {
ExpressionAttributeValues: {
':type' : {S: 'recipe'},
},
KeyConditionExpression: 'item_type = :type',
TableName: 'recipes',
IndexName: 'item_type-index',
};
const [data, setData] = useState([]);
useEffect(() => {
ddb.query(params, function (err, data) {
if (data) {
console.log('length: ', data['Items'].length)
setData(data['Items'].length);
} else {
console.log(err);
}
});
}, [props.title]);
var navigate = useNavigate();
const saveNew = () => {
var currentTitle = document.getElementById('title').value
var currentYield = document.getElementById('yield').value
var currentTime = document.getElementById('time').value
var currentPicture = document.getElementById('picture').value
var instNodes = document.querySelectorAll('[id=instructions]')
var currentInstructions = Array.prototype.map.call(instNodes, function(t) { return {S : t.value}; });
var ingNodes = document.querySelectorAll('[id=ingredients]')
var currentIngredients = Array.prototype.map.call(ingNodes, function(t) { return {S : t.value}; });
var nvNodes = document.querySelectorAll('[id=nutrientsValue]')
var currentNutrientsValue = Array.prototype.map.call(nvNodes, function(t) { return {S : t.value}; });
var ntNodes = document.querySelectorAll('[id=nutrientsType]')
for(const element of nt_nodes){
var regex = /^\s*$|[a-z]|[a-zA-Z] ([A-Z][a-z] ) $/g
if (regex.test(element.value) === false){
element.classList.add('err')
alert('"' element.value '" must be in camelCase.')
return false
}
}
var currentNutrientsType = Array.prototype.map.call(ntNodes, function(t) { return t.value; });
var nutrientsMap = {};
currentNutrientsType.forEach((key, i) => nutrientsMap[key] = currentNutrientsValue[i]);
// Call DynamoDB to add the item to the table
var params = {
TableName: 'recipes',
Item: {
'recipe_index': {N: String(data)},
'title': {S : currentTitle},
'yields': {S : currentYield},
'cook_time': {S : currentTime},
'image': {S: currentPicture},
'instructions': {L: currentInstructions},
'ingredients' : {L: currentIngredients},
'nutrients' : {M: nutrientsMap},
'item_type' : {S: 'recipe'},
},
};
ddb.putItem(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data);
}
});
// go back to display page and refresh.
navigate(currentTitle);
window.location.reload(false);
}
return(<button name={props.name} className={props.className} onClick={saveNew} type="button">Save</button>)
}
CodePudding user response:
You cannot save a value as undefined, which is happening when you do not define nutrients.
Try and conditionally set nutrients
Item: {
'recipe_index': {N: String(data)},
'title': {S : currentTitle},
'yields': {S : currentYield},
'cook_time': {S : currentTime},
'image': {S: currentPicture},
'instructions': {L: currentInstructions},
'ingredients' : {L: currentIngredients},
...(nutrientsMap==undefined) && {'nutrients':{M: nutrientsMap}},
'item_type' : {S: 'recipe'},
}