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

DynamoDB查询报TypeError:无法读取undefined的'0'属性,求排查

问题描述

我有一个名为AllowListedItems的DynamoDB表,包含Id、name和ignoreNoTraffic字段,且在name字段上创建了名为name-index的GSI。尝试通过name查询ignoreNoTraffic的值时,AWS SDK V3的TypeScript代码报错,但AWS SDK V2的JavaScript代码可正常执行。

AWS SDK V3 TypeScript代码

业务逻辑代码

import { DynamoDB, GetItemCommand, ScanCommand, QueryCommand } from "@aws-sdk/client-dynamodb";
import { unmarshall } from "@aws-sdk/util-dynamodb";

private async getIgnoreNoTraffic(): Promise<boolean> {
    const params = {
        TableName: Tables.ALLOW_LISTED_ITEMS,
        IndexName: "name-index",
        KeyConditionExpression: "#nameAttr = :nameValue",
        ExpressionAttributeNames: {
            "#nameAttr": "name" 
        },
        ExpressionAttributeValues: {
            ":nameValue": this.name,
        },
    };

    try {
        const items = await dynamodbUtils.queryValuesFromDB(params);

        if (items.length > 0) {
            const item = items[0];
            console.log("Received item:", item);

            if (item. ignoreNoTraffic !== undefined) {
                return item. ignoreNoTraffic.BOOL || false;  
            } else {
                return false;
            }
        } else {
            console.log("Item could not be fetched from the table using name");
            return false;
        }
    } catch (error) {
        console.error("Error fetching ignoreNoTraffic by name:", error);
        throw error;
    }
}

DynamoDB工具函数

export async function queryValuesFromDB(params: any) {
console.log("Querying DynamoDB with params2:", JSON.stringify(params, null, 2));

try {
    const data = await client.send(new QueryCommand(params));

    if (!data) {
        console.error("DynamoDB returned undefined or null data.");
        throw new Error("DynamoDB returned undefined or null data.");
    }

    console.log("Received raw data from DynamoDB:", JSON.stringify(data, null, 2));

    if (!data.Items) {
        console.log("Items field is missing from the data.");
        throw new Error("DynamoDB response does not contain 'Items'.");
    }

    if (data.Items.length > 0) {
        console.log("Successfully retrieved items:", data.Items);
        return data.Items; // Directly return the items as JSON
    } else {
        console.log("No items found for the query.");
        return [];
    }
} catch (error) {
    console.error("Error executing DynamoDB query:", error);

    if (error instanceof Error) {
        console.error("Error message:", error.message);
        throw new Error(`DynamoDB Query Error: ${error.message}`);
    } else {
        console.error("Unknown error occurred:", JSON.stringify(error));
        throw new Error("An unknown error occurred during DynamoDB query.");
    }
}

错误信息

ERROR   Error while sending query command to DynamoDB: TypeError: Cannot read properties of undefined (reading '0')

日志信息

INFO    Querying DynamoDB with params3: 
{
"TableName": "AllowListedItems",
"IndexName": "name-index",
"KeyConditionExpression": "#nameAttr = :nameValue",
"ExpressionAttributeNames": {
    "#nameAttr": "name"
},
"ExpressionAttributeValues": {
    ":nameValue": "development"
}
}

可正常运行的AWS SDK V2 JavaScript代码

const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB();
const docClient = new AWS.DynamoDB.DocumentClient();

async function queryValuesFromDB(params) {
    console.log("Querying DynamoDB with params:", JSON.stringify(params, null, 2));

    try {
        const data = await docClient.query(params).promise();
        console.log("Received raw data from DynamoDB:", JSON.stringify(data, null, 2));

        if (data && data.Items && data.Items.length > 0) {
            console.log("Successfully retrieved items:", data.Items);
            return data.Items; 
        } else {
            console.log("No items found for the query.");
            return [];
        }
    } catch (error) {
        console.error("Error executing DynamoDB query:", error.message || error);
        throw new Error(`DynamoDB Query Error: ${error.message || error}`);
    }
}

async function getIgnoreNoTraffic(name) {
    const params = {
        TableName: 'AllowListedItems', 
        IndexName: 'name-index', 
        KeyConditionExpression: "#nameAttr = :nameValue",
        ExpressionAttributeNames: {
            "#nameAttr": "name" 
        },
        ExpressionAttributeValues: {
            ":nameValue": name, 
        },
    };

    try {
        const items = await queryValuesFromDB(params);
        if (items.length > 0) {
            const item = items[0];
            if (item. ignoreNoTraffic !== undefined) {
                return item. ignoreNoTraffic;
            } else {
                return false;
            }
        } else {
            console.log("Item could not be fetched from the table using name");
            return false;
        }
    } catch (error) {
        console.error("Error fetching ignoreNoTraffic by name:", error);
        throw error;
    }
}

exports.handler = async (event) => {
    const name = event.name || "test-name"; 
    try {
        const ignoreNoTraffic = await getIgnoreNoTraffic(name);
        console.log("Ignore result:", ignoreNoTraffic);
        return {
            statusCode: 200,
            body: JSON.stringify({
                message: "Success",
                ignoreNoTraffic: ignoreNoTraffic
            }),
        };
    } catch (error) {
        return {
            statusCode: 500,
            body: JSON.stringify({
                message: "Error",
                error: error.message,
            }),
        };
    }
};

问题原因
  1. SDK数据格式不兼容:V3使用的是低阶DynamoDB客户端,要求ExpressionAttributeValues必须传入带类型标识的DynamoDB原生格式(如{ S: "value" }),但你直接传入了字符串,导致查询失败,工具函数返回的items异常。而V2使用的DocumentClient会自动处理格式转换,所以可正常运行。
  2. 代码语法错误:业务代码中item. ignoreNoTraffic的点后多了空格,实际访问的是带前导空格的属性名,与表中实际字段ignoreNoTraffic不匹配,导致读取属性时返回undefined,进而触发读取.BOOL的错误。
  3. GSI投影属性缺失(潜在风险):如果name-index的投影属性未包含ignoreNoTraffic,即使查询成功,也不会返回该字段,同样会导致属性读取失败。

解决方案

方案1:改用DynamoDBDocumentClient(推荐)

使用V3高阶客户端DynamoDBDocumentClient,自动处理数据格式转换,和V2的DocumentClient逻辑一致:

修改工具函数

import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";
import { DynamoDB } from "@aws-sdk/client-dynamodb";

const client = new DynamoDB({});
const docClient = DynamoDBDocumentClient.from(client);

export async function queryValuesFromDB(params: any) {
    console.log("Querying DynamoDB with params:", JSON.stringify(params, null, 2));

    try {
        const data = await docClient.send(new QueryCommand(params));
        return data.Items || [];
    } catch (error) {
        console.error("Error executing DynamoDB query:", error);
        if (error instanceof Error) {
            throw new Error(`DynamoDB Query Error: ${error.message}`);
        } else {
            throw new Error("An unknown error occurred during DynamoDB query.");
        }
    }
}

修正业务代码的语法错误

if (items.length > 0) {
    const item = items[0];
    console.log("Received item:", item);

    if (item.ignoreNoTraffic !== undefined) {
        return item.ignoreNoTraffic || false;  
    } else {
        return false;
    }
}

方案2:手动处理数据格式(不推荐)

若坚持使用低阶DynamoDB客户端,需手动处理参数格式和数据转换:

修改查询参数的格式

const params = {
    TableName: Tables.ALLOW_LISTED_ITEMS,
    IndexName: "name-index",
    KeyConditionExpression: "#nameAttr = :nameValue",
    ExpressionAttributeNames: {
        "#nameAttr": "name" 
    },
    ExpressionAttributeValues: {
        ":nameValue": { S: this.name }, // 字符串类型需用S标识
    },
};

工具函数中添加数据转换

import { unmarshall } from "@aws-sdk/util-dynamodb";

// ...其他代码
if (data.Items.length > 0) {
    return data.Items.map(item => unmarshall(item)); // 转换为普通JSON对象
} else {
    return [];
}

同样修正业务代码的空格问题

和方案1中的修正一致,确保访问正确的字段名。

额外检查

  • 确认name-index的投影属性包含ignoreNoTraffic,可在AWS控制台DynamoDB表的GSI设置中查看修改。
  • 验证DynamoDB客户端已正确初始化,且Lambda角色或执行账号具有访问该表和GSI的权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 23:32:04