You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

未包含nutrients时无法向DynamoDB推送数据的求助

问题描述
  • 表单数据推送到DynamoDB时,包含nutrients字段时正常,缺失该字段则推送失败,报错Error RequestAbortedError: Request aborted
  • 需求:除recipe_index(脚本顶部查询自动生成)和item_type(固定为{S: 'recipe'})外,其他任意字段缺失都能正常完成推送
  • 排查情况:未发现代码中有依赖nutrients存在的逻辑,调整简化代码、谷歌搜索均未找到有效解决方法,刚接触DynamoDB、JS和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=&quot;button&quot;>Save</button>)
}
问题分析

核心原因是DynamoDB不允许存储空的Map类型(M: {}):当没有nutrients数据时,nutrientsMap是空对象,此时将nutrients: {M: nutrientsMap}加入Item会导致请求被DynamoDB中止,触发RequestAbortedError。

另外代码还有2个潜在问题:

  • 变量名错误:循环中使用了未定义的nt_nodes,实际应为ntNodes
  • 异步操作未处理:putItem是异步请求,直接调用navigate和reload会导致请求还未完成就跳转页面
修复方案

1. 处理空nutrients字段

仅当nutrientsMap有内容时,才将其加入Item对象:

// 先构建基础Item对象
const 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},
    'item_type' : {S: 'recipe'},
};

// 只有nutrientsMap非空时才添加该字段
if (Object.keys(nutrientsMap).length > 0) {
    item.nutrients = {M: nutrientsMap};
}

var params = {
    TableName: 'recipes',
    Item: item,
};

2. 修复变量名错误

将循环中的nt_nodes改为ntNodes:

for(const element of ntNodes){
    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
    }
}

3. 优化异步操作逻辑

等待putItem请求完成后再执行页面跳转:

ddb.putItem(params, function(err, data) {
    if (err) {
        console.log("Error", err);
    } else {
        console.log("Success", data);
        // 请求成功后再跳转刷新
        navigate(currentTitle);
        window.location.reload(false);
    }
});

4. (可选)改用React受控组件

避免直接操作DOM,用state管理表单值,示例:

// 组件内定义表单状态
const [title, setTitle] = useState('');

// 表单输入框写法
<input 
    id="title" 
    value={title} 
    onChange={(e) => setTitle(e.target.value)} 
/>

// 获取值时直接使用title变量即可
var currentTitle = title;

内容的提问来源于stack exchange,提问作者Art Vandalay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 06:46:05