Lambda中DynamoDocumentClient未自动反序列化结果问题排查
问题:DynamoDBDocumentClient未自动反序列化结果,及SS类型转换优化
我编写了一个Lambda函数从DynamoDB获取记录,按AWS文档配置了DynamoDBDocumentClient(ddbDocClient),配置文件ddbDocClient.js代码如下:
const { DynamoDBDocumentClient } = require("@aws-sdk/lib-dynamodb"); const { DynamoDBClient } = require("@aws-sdk/client-dynamodb"); const REGION = "us-west-2" const ddbClient = new DynamoDBClient({ region: REGION }); const marshallOptions = { convertEmptyValues: false, // false, by default. removeUndefinedValues: false, // false, by default. convertClassInstanceToMap: false, // false, by default. }; const unmarshallOptions = { wrapNumbers: false, // false, by default. }; const translateConfig = { marshallOptions, unmarshallOptions }; const ddbDocClient = DynamoDBDocumentClient.from(ddbClient, translateConfig); module.exports.ddbDocClient = ddbDocClient;
随后使用该客户端执行查询操作,代码如下:
const { ddbDocClient } = require("./ddbDocClient.js"); const { QueryCommand } = require("@aws-sdk/client-dynamodb"); const listsTableName = "my_list_name"; /// Fetches lists owned by the current user async function getListIDs(userid) { const params = { TableName: listsTableName, IndexName: 'owner-index', KeyConditionExpression: '#owner = :owner', ExpressionAttributeNames: { "#owner": "owner" }, ExpressionAttributeValues: {":owner": { "S": userid }} }; const command = new QueryCommand(params); const dynamoData = await ddbDocClient.send(command); const lists = dynamoData.Items; console.log(lists); }
但返回结果仍是带S、SS等类型标记的原始格式:
[ { things: { SS: [Array] }, owner: { S: '0d5e789b-009b-4ba0-80a7-12065d0908b5' }, collaborator: { S: 'A845E8EF-956B-467D-B57B-6D959BB78C98' }, id: { S: '0C629140-6651-43E9-8D9F-3E52EBAD94F3' } }, { owner: { S: '0d5e789b-009b-4ba0-80a7-12065d0908b5' }, things: { SS: [Array] }, collaborator: { S: 'ttttt' }, id: { S: 'xxxxx89b-009b-4ba0-80a7-12065d0908b5' } } ]
我原本认为DocumentClient应该自动完成反序列化,目前只能手动处理,还需额外将SS类型的Set转换为数组:
const lists = dynamoData.Items; // From DynamoDB JSON var unmarshalledLists = lists.map((i) => unmarshall(i)); if (unmarshalledLists.length > 0) { // If we have at least 1 list we need to convert the things Set to Array unmarshalledLists.forEach(function(list) { const things = Array.from(list.things); list.things = things; }); return unmarshalledLists; } else { // No results to return throw("No lists found"); }
请问:
- 哪里操作错误导致无法自动反序列化?
- 是否有更简洁的方法将SS结果转换为数组?
解答
1. 自动反序列化失效的原因
核心错误是使用了错误的QueryCommand来源:你导入的是@aws-sdk/client-dynamodb中的QueryCommand,这是针对原始DynamoDB客户端的命令,不会触发DocumentClient的自动序列化/反序列化逻辑。
正确的做法是从@aws-sdk/lib-dynamodb导入QueryCommand,这个库才是为DocumentClient设计的配套命令集,能自动处理参数的marshall(序列化)和结果的unmarshall(反序列化)。
修正后的查询代码
const { ddbDocClient } = require("./ddbDocClient.js"); // 从lib-dynamodb导入QueryCommand const { QueryCommand } = require("@aws-sdk/lib-dynamodb"); const listsTableName = "my_list_name"; async function getListIDs(userid) { const params = { TableName: listsTableName, IndexName: 'owner-index', KeyConditionExpression: '#owner = :owner', ExpressionAttributeNames: { "#owner": "owner" }, // 无需手动添加类型标记,直接传入原始值即可 ExpressionAttributeValues: {":owner": userid} }; const command = new QueryCommand(params); const dynamoData = await ddbDocClient.send(command); const lists = dynamoData.Items; // 此时lists已经是反序列化后的普通对象,不再有S/SS标记 console.log(lists); return lists; }
2. 简化SS转数组的方法
默认情况下,DocumentClient会把SS类型反序列化为Set对象。如果想直接得到数组,无需手动遍历转换,只需在配置DocumentClient的unmarshallOptions中添加convertSetsToArrays: true即可。
修正后的配置文件ddbDocClient.js
const { DynamoDBDocumentClient } = require("@aws-sdk/lib-dynamodb"); const { DynamoDBClient } = require("@aws-sdk/client-dynamodb"); const REGION = "us-west-2" const ddbClient = new DynamoDBClient({ region: REGION }); const marshallOptions = { convertEmptyValues: false, removeUndefinedValues: false, convertClassInstanceToMap: false, }; const unmarshallOptions = { wrapNumbers: false, // 添加该配置,自动将Set转换为数组 convertSetsToArrays: true }; const translateConfig = { marshallOptions, unmarshallOptions }; const ddbDocClient = DynamoDBDocumentClient.from(ddbClient, translateConfig); module.exports.ddbDocClient = ddbDocClient;
这样修改后,查询返回的things字段会直接是数组类型,不需要再手动调用Array.from()处理。
内容的提问来源于stack exchange,提问作者Darren
相关产品推荐
相关产品推荐

