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>) }
Advertisement
Answer
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'}, }