AWS NodeJS SDK V3 DynamoDB UpdateItem - TypeError: Cannot read property '0' of undefined

AWS NodeJS SDK V3 DynamoDB UpdateItem - TypeError: Cannot read property '0' of undefined

我正在尝试使用适用于 NodeJS 的新 AWS SDK V3 让基本的数据库更新操作在 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 进行更新的任何帮助,我们将不胜感激!

几个更正:

  • 传递值时,我们需要传递带有类型的对象。所以,而不是 user.userid.S 传递整个 user.userid。由于它无法确定类型,它假定为一个数组并尝试获取数组的第一个元素并导致该错误。
  • 数值,应该简单地作为 '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);
  });

您可以使用 @aws-sdk/lib-dynamodb 包,它更接近 aws-sdk 的 v2 样式。来自 documentation:

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.[=17 的输入=]

这是他们的示例代码:

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",
  },
});