Skip to content
Advertisement

Cannot push to DynamoDB without the inclusion of a certain value

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'},
            }
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement