开发者问题收集

AWS NodeJS SDK V3 DynamoDB UpdateItem - TypeError:无法读取未定义的属性“0”

2021-03-11
22819

我正在尝试使用新的 AWS SDK V3 for NodeJS 在 nodejs 中执行基本数据库更新操作。

我尝试更新的数据对象如下所示:

{
  auth: { BOOL: false },
  username: { S: 'siegbert' },
  secondsLeft: { N: 49985 },
  userid: { S: '123456' }
}

在同一个文件中,我已经使用 SDK V3 成功执行了 GetItemCommand。

不幸的是,我在使用 AWS SDK v3 时不断收到一个非常奇怪的错误,而使用 SDK v2 时,完全相同的参数似乎可以正常工作。我尝试查看文档,但更新操作尚未得到很好的记录。

var params = {
    TableName: "tableXYZ",
    Key: {
        userid: user.userid.S,
    },
    UpdateExpression: "SET secondsLeft = :newsecondsLeft", 
    ExpressionAttributeValues: { 
        ":newsecondsLeft": user.secondsLeft.N,
    },
    ReturnValues: "UPDATED_NEW"
};


try {
        const data = await dbclient.send(new UpdateItemCommand(params));
        console.log("data:" + JSON.stringify(data));
        return true;
    } catch (error) {
        console.error(error);
        return false;
    }

这基本上会引发

TypeError: Cannot read property '0' of undefined
    at Object.AttributeValue.visit (XX\node_modules\@aws-sdk\client-dynamodb\dist\cjs\models\models_0.js:1101:40)
    at XX\node_modules\@aws-sdk\client-dynamodb\dist\cjs\protocols\Aws_json1_0.js:5074:20
    at Array.reduce (<anonymous>)
    at serializeAws_json1_0ExpressionAttributeValueMap (XX\node_modules\@aws-sdk\client-dynamodb\dist\cjs\protocols\Aws_json1_0.js:5068:34)
    at serializeAws_json1_0UpdateItemInput (XX\node_modules\@aws-sdk\client-dynamodb\dist\cjs\protocols\Aws_json1_0.js:6067:40)
    at Object.serializeAws_json1_0UpdateItemCommand (XX\node_modules\@aws-sdk\client-dynamodb\dist\cjs\protocols\Aws_json1_0.js:474:27)
    at serialize (XX\node_modules\@aws-sdk\client-dynamodb\dist\cjs\commands\UpdateItemCommand.js:42:30)
    at XX\node_modules\@aws-sdk\middleware-serde\dist\cjs\serializerMiddleware.js:5:27
    at XX\node_modules\@aws-sdk\middleware-logger\dist\cjs\loggerMiddleware.js:6:28

当使用完全相同的参数但使用 SDK v2 时,它可以工作:

var docClient = new AWS.DynamoDB.DocumentClient();

docClient.update(params, function (err, data) {
    if (err) {
        console.error("Unable to update item. Error JSON:", JSON.stringify(err, null, 2));
    } else {
        console.log("UpdateItem succeeded:", JSON.stringify(data, null, 2));
    }
});

任何关于如何使用 SDK V3 进行更新的帮助都将不胜感激!

3个回答

几处更正:

  • 传递值时,我们需要传递具有类型的对象。因此,传递整个 user.userid 而不是 user.userid.S 。由于无法确定类型,因此它假设为数组并尝试获取数组的第一个元素,从而导致该错误。
  • 数字值应简单地作为类型为“N”的字符串值传递,例如 secondsLeft: { N: "49985"

这是更新后的代码。

const { DynamoDB, UpdateItemCommand } = require("@aws-sdk/client-dynamodb");
const dbclient = new DynamoDB({ region: "us-east-1" });
const user = {
  auth: { BOOL: false },
  username: { S: "siegbert" },
  secondsLeft: { N: "49985" },
  userid: { S: "123456" },
};
var params = {
  TableName: "tableXYZ",
  Key: {
    id: user.userid,
  },
  UpdateExpression: "SET secondsLeft = :newsecondsLeft",
  ExpressionAttributeValues: {
    ":newsecondsLeft": user.secondsLeft,
  },
  ReturnValues: "UPDATED_NEW",
};

dbclient
  .send(new UpdateItemCommand(params))
  .then((result) => {
    console.log("data:" + result);
  })
  .catch((err) => {
    console.log("err", err);
  });
Balu Vyamajala
2021-03-11

使用 lib-dynamodb 模块中的 DynamoDBDocumentClient 可以更轻松地完成此操作:

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

const test = async () => {

    const client = new DynamoDBClient({region: 'eu-west-1'})

    const params = {
        TableName: "tableXYZ",
        Item: 
            {
            userid: 'userId',
                ...user
        }
    }

    const docClient = DynamoDBDocumentClient.from(client);

    try {
        const response = await docClient.send(new PutCommand(params))
        console.log(response)
    } catch (e) {
        console.error(e)
    }
}

test()

(这可以作为独立节点脚本运行)

Ciryon
2022-06-23

您可以使用 @aws-sdk/lib-dynamodb 软件包,它是 aws-sdk v2 样式的替代品。摘自 文档

The document client simplifies working with items in Amazon DynamoDB by abstracting away the notion of attribute values. This abstraction annotates native JavaScript types supplied as input parameters, as well as converts annotated response data to native JavaScript types.

这也许是直接使用 @aws-sdk/client-dynamodb 的更简洁的替代方案(并且更易于升级),尽管您仍然需要实例化该客户端作为使用 @aws-sdk/lib-dynamodb 的输入。

这是他们的示例代码:

import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; // ES6 import
// const { DynamoDBClient } = require("@aws-sdk/client-dynamodb"); // CommonJS import
import { DynamoDBDocumentClient, PutCommand } from "@aws-sdk/lib-dynamodb"; // ES6 import
// const { DynamoDBDocumentClient, PutCommand } = require("@aws-sdk/lib-dynamodb"); // CommonJS import

const client = new DynamoDBClient({});
const ddbDocClient = DynamoDBDocumentClient.from(client);

await ddbDocClient.put({
  TableName,
  Item: {
    id: "2",
    content: "content from DynamoDBDocument",
  },
});
Brent L
2021-11-10