【问题标题】:DynamoDB get item TypeScript hellDynamoDB 获取项目 TypeScript 地狱
【发布时间】:2022-04-05 06:40:41
【问题描述】:

谁能解释一下在调用DocumentClient.get时如何使用GetItemInput类型?

如果我传入任何类型的对象 get 有效,但如果我尝试强烈键入 params 对象,则会收到此错误:

ValidationException: The provided key element does not match the schema

这是我的 lambda 函数代码,我将参数作为 any 类型传递:

export const get: Handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {

  console.log(event.pathParameters)
  if (!event.pathParameters) {
    throw Error("no path params")
  }

  const params: any = {
    Key: {
      id: event.pathParameters.id
    },
    TableName: table
  }

  console.log(params)
  try {
    const result: any = await dynamoDb.get(params).promise()
    return {
      body: JSON.stringify(result.Item),
      statusCode: result.$response.httpResponse.statusCode
    }

  } catch (error) {
    console.log(error)
    return {
      body: JSON.stringify({
        message: `Failed to get project with id: ${event.pathParameters!.id}`
      }),
      statusCode: 500
    }
  }
}

这是我尝试让它与类型 GetItemInput 一起使用

export const get: Handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {

  console.log(event.pathParameters)
  if (!event.pathParameters) {
    throw Error("no path params")
  }

  const params: GetItemInput = {
    Key: {
      "id": { S: event.pathParameters.id }
    },
    TableName: table
  }

  console.log(params)
  try {
    const result: any = await dynamoDb.get(params).promise()
    return {
      body: JSON.stringify(result.Item),
      statusCode: result.$response.httpResponse.statusCode
    }

  } catch (error) {
    console.log(error)
    return {
      body: JSON.stringify({
        message: `Failed to get project with id: ${event.pathParameters!.id}`
      }),
      statusCode: 500
    }
  }
}

如果我像以前一样离开Key ala:

const params: GetItemInput = {
  Key: {
    id: event.pathParameters.id
  },
  TableName: table
}

不出所料,我收到了类型错误。但无法理解我如何形成我的Key,这样我就得不到ValidationException

注意id 字段在DynamoDB 中属于String 类型。

【问题讨论】:

  • 您在哪里找到 GetItemInput?对我来说,它看起来不像 JS SDK 的一部分。我可以看到它是 Ruby 和 Go SDK 的一部分。
  • 这是我的导入语句,它有效,所以假设它在 dynamo-db 类型中导入 { AttributeValue, GetItemInput, ScanInput, StringAttributeValue } from "aws-sdk/clients/dynamodb" docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/…
  • 该链接表明这应该是有效的... const params: GetItemInput = { Key: { "id": event.pathParameters.id }, TableName: table },但是我得到一个类型错误说"type 'string' 与 type 'AttributeValue' 没有共同的属性"
  • 我在链接中看不到任何引用?
  • SDK 专门抽象出属性值并改用本机 JSON 对象(请参阅您链接的页面顶部)。我可能是错的,但我不认为你正在尝试的是可能的。

标签: amazon-web-services aws-lambda amazon-dynamodb aws-sdk aws-sdk-js


【解决方案1】:

我认为您混合了两个不同的客户端定义文件 DynamoDBDynamoDB.DocumentClient。在您使用DynamoDB.DocumentClient 客户端的同时,您正在使用来自DynamoDB 的接口DynamoDB.Types.GetItemInput

你应该使用DynamoDB.DocumentClient.GetItemInput:

import {DynamoDB} from 'aws-sdk';
const dynamo = new DynamoDB.DocumentClient({apiVersion: '2012-08-10'});

...
const params: DynamoDB.DocumentClient.GetItemInput = {
    TableName: table,
    Key: {
        id: event.pathParameters.id
    }
};
const result = await this.dynamo.get(params).promise();

【讨论】:

    【解决方案2】:

    @ttulka 的回答很完美,但补充一下,我也遇到了同样的问题,我花了 5 分钟时间来消除现在从官方 AWS JS 开发工具包访问 DynamoDB 的多种不同方式,这确实有助于消除歧义。

    读5分钟就是我的答案,看完之后你就明白了;

    https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_lib_dynamodb.html

    tldr;是;

    • 知道您使用的是哪个 AWS JS 版本,无论是 v2 还是 v3,当您从 Internet 上提取其他样本时请注意它们可能适用于旧版本 - 您应该能够根据导入来判断您正在使用,这里是 v3 导入的样子:

    import { DynamoDB } from "@aws-sdk/client-dynamodb"; // ES6 import
    import { DynamoDBDocument, PutCommandInput } from "@aws-sdk/lib-dynamodb"; // ES6 import
    • 您可能希望使用 DocumentClient 而不是原始 DynamoDB,您需要在其中指定所有属性的原始类型 - 为了成功执行此操作,您的 DynamoDB JS 对象必须以正确的方式构建(上面的文档解释了具体如何)
    • 知道您使用的是“基本”还是“完整版”的 DynamoDB,因为如果您使用的是完整版,您将可以访问 TS 中的更多类型/提示
    • 并且您可能希望使用 client-dynamodb 和 lib-dynanmodb,因为后者是 SDK 的附加功能,可帮助您简化操作(确实如此)

    【讨论】:

    • “它们可能适用于旧版本”——这在处理 AWS 开发工具包时非常重要。他们的文档通常不足以解释这一点。
    【解决方案3】:

    DynamoDbClient

    对于像我这样懒得制作自己的 dynamoDB 客户端并想要复制和粘贴的人来说,这是我编写的一些代码:

    import { AttributeValue, DynamoDB, GetItemInput, PutItemCommandOutput, PutItemInput, QueryCommandInput } from "@aws-sdk/client-dynamodb";
    import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
    
    export default class DynamoDbClient {
        dynamoDB: DynamoDB;
        tableName: string;
        constructor(tableName: string) {
            this.dynamoDB = new DynamoDB({});
            this.tableName = tableName
        }
    
        async getItem<T>(inputKeys: DynamoDbClientGetItemInput): Promise<T | UnmarshalledAny> {
            const params: GetItemInput = {
                TableName: this.tableName,
                Key: marshall(inputKeys)
            };
            const result = await this.dynamoDB.getItem(params);
            if (!result || !result.Item) {
                return null
            }
            return unmarshall(result.Item)
        }
    
        async query<T>(input: Partial<QueryCommandInput>): Promise<T | UnmarshalledAny> {
            const params: QueryCommandInput = {
                TableName: this.tableName,
                ...input
            };
            const result = await this.dynamoDB.query(params);
            if (!result.Items) {
                return []
            }
            return this.unmarshallList(result.Items)
        }
    
        unmarshallList(items: MarshalledItem[]) {
            const unmarshalledItems = []
            for (let index = 0; index < items.length; index++) {
                const item = items[index];
                unmarshalledItems.push(unmarshall(item))
            }
            return unmarshalledItems
        }
    
        async putItem(inputItem: DynamoDbClientPutItemInput): Promise<PutItemCommandOutput> {
            const params: PutItemInput = {
                TableName: this.tableName,
                Item: marshall(inputItem, { removeUndefinedValues: true })
            };
            return await this.dynamoDB.putItem(params);
        }
    }
    
    export interface DynamoDbClientGetItemInput { id: string, pk: string }
    export interface DynamoDbClientPutItemInput { id: string, pk: string, data: any }
    
    export interface UnmarshalledAny {
        [key: string]: any;
    }
    
    export interface MarshalledItem {
        [key: string]: AttributeValue;
    }
    
    

    您可以使用以下方式安装库:

    npm i @aws-sdk/client-dynamodb @aws-sdk/util-dynamodb
    

    您需要将您的密钥名称更改为 dynamoDB 中的任何名称,我的称为 pkid

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多