DynamoDB 获取项目 TypeScript 地狱
DynamoDB get item TypeScript hell
谁能解释一下在调用 DocumentClient.get
时如何使用 GetItemInput
类型?
如果我传入任何类型的对象 get
都可以,但如果我尝试强键入参数对象,我会收到此错误:
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
类型。
我认为您混合了两个不同的客户端定义文件 DynamoDB
and DynamoDB.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();
@ttulka 的回答是完美的,但补充一点,我遇到了同样的问题,花 5 分钟来消除现在许多从官方 AWS JS SDK 访问 DynamoDB 的不同方式的歧义真的很有帮助。
看完5分钟就是我的答案,看完你就明白了;
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_lib_dynamodb.html
长篇大论;是;
- 知道您使用的是哪个 AWS JS 版本,是 v2 还是 v3,并且当您从互联网上提取其他样本时要注意它们可能适用于旧版本 - 您应该能够根据您正在使用的导入,这是 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 中访问更多 types/hints
- 您可能想使用 client-dynamodb 和 lib-dynanmodb,因为后者是 SDK 的一个额外功能,可以帮助简化操作(确实如此)
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 中的任何名称,我的名称为 pk
和 id
谁能解释一下在调用 DocumentClient.get
时如何使用 GetItemInput
类型?
如果我传入任何类型的对象 get
都可以,但如果我尝试强键入参数对象,我会收到此错误:
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
类型。
我认为您混合了两个不同的客户端定义文件 DynamoDB
and DynamoDB.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();
@ttulka 的回答是完美的,但补充一点,我遇到了同样的问题,花 5 分钟来消除现在许多从官方 AWS JS SDK 访问 DynamoDB 的不同方式的歧义真的很有帮助。
看完5分钟就是我的答案,看完你就明白了;
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_lib_dynamodb.html
长篇大论;是;
- 知道您使用的是哪个 AWS JS 版本,是 v2 还是 v3,并且当您从互联网上提取其他样本时要注意它们可能适用于旧版本 - 您应该能够根据您正在使用的导入,这是 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 中访问更多 types/hints
- 您可能想使用 client-dynamodb 和 lib-dynanmodb,因为后者是 SDK 的一个额外功能,可以帮助简化操作(确实如此)
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 中的任何名称,我的名称为 pk
和 id