如何为具有关系的对象创建 AppSync DynamoDB 解析器
How to create AppSync DynamoDB resolver for object with relationships
我有一个 DynamoDB table,它有 Games
和 Players
。我目前有以下适用于我的 AppSync getGame 查询的 Lambda 解析器。问题是,是否可以使用执行相同操作的速度模板编写 DynamoDB 解析器,这样我就可以避免 lambda 调用。
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event) => {
let result = null;
let params;
switch(event.field) {
case "getGame":
const id = event.arguments.id;
if (!id) {
throw new Error('Missing game id');
};
params = {
TableName: 'games',
KeyConditionExpression: 'pk = :pk AND sk = :sk',
ExpressionAttributeValues: {
':pk': 'game',
':sk': `meta_${id}`
}
};
const game = (await docClient.query(params).promise()).Items[0];
// get players
const gameKey = `game_${game.sk.split('_')[1]}_${game.sk.split('_')[2]}`;
params = {
TableName: 'games',
KeyConditionExpression: 'pk = :pk AND begins_with(sk, :sk)',
ExpressionAttributeValues: {
':pk': gameKey,
':sk': 'player_'
}
};
game.players = (await docClient.query(params).promise()).Items;
result = game;
break;
}
return result;
};
结果看起来像
{
"gsipk": "NEW_OPEN",
"sk": "meta_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"gsisk": "level_1_players_4",
"pk": "game",
"players": [
{
"gsipk": "player_3a7bb19c-0ccd-42df-a606-acd8b1f5e288",
"gsisk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"points": 0,
"num": 4,
"place": null,
"sk": "player_3a7bb19c-0ccd-42df-a606-acd8b1f5e288",
"pieces": [],
"wilds": 0,
"pk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"color": "gold",
"pows": 0
},
{
"gsipk": "player_96b772b1-4127-43da-b550-029d5c632675",
"gsisk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"points": 0,
"num": 2,
"place": null,
"sk": "player_96b772b1-4127-43da-b550-029d5c632675",
"pieces": [],
"wilds": 0,
"pk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"color": "blue",
"pows": 0
},
{
"gsipk": "player_9d30c675-930f-401b-ac5f-8db32bb2acb8",
"gsisk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"points": 0,
"num": 3,
"place": null,
"sk": "player_9d30c675-930f-401b-ac5f-8db32bb2acb8",
"pieces": [],
"wilds": 0,
"pk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"color": "green",
"pows": 0
},
{
"gsipk": "player_ab179ad1-a160-44f8-b438-0e93385b6c47",
"gsisk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"points": 0,
"num": 1,
"place": null,
"sk": "player_ab179ad1-a160-44f8-b438-0e93385b6c47",
"pieces": [],
"wilds": 0,
"pk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"color": "red",
"pows": 0
}
]
}
除非您重新映射数据以便能够在一个请求中获取所有项目,否则您将需要 Pipeline resolvers.。总而言之,管道是一些解析器,它们被包裹在 before/after 模板中。
在您的情况下,这些 before/after 模板并未真正使用,因此基本设置为:
在模板之前(不需要任何东西,所以一个空的 json 就可以了)
{}
模板之后(传递之前调用的结果)
$util.toJson($ctx.result)
那么您将拥有 2 个 DynamoDB 解析器。这些与您之前可能完成的其他 DynamoDB 解析器相同,除了在第二个中,为了访问第一个 DynamoDB 解析器结果,您将使用 $ctx.prev.result
。因此,假设您在第一次调用的响应中将游戏 ID 传递为:
{
"game_id": "$ctx.result.get('theGameId')",
...
}
然后可以在第二个请求模板中访问 $ctx.prev.result.game_id
。您也可以使用存储代替 - $ctx.stash.put()
和 $ctx.prev.get()
。如果您需要在 BEFORE 请求中执行某些操作(我们现在留空的第一个请求)并将其传递给整个解析器,则存储很有用。
好的,感谢@cyberwombat 的评论:
Unless you remap your data to be able to fetch all items in one request
我想通了。首先,我不得不重构我的 table 一点。我将主键(哈希)更改为 game_<uuid>
,然后使用 meta_<timestamp>
等排序键(范围)引用游戏详细信息,并使用 player_<uuid>
等排序键引用玩家。
一旦我这样做了,我就能够使用这个解析器来查询和 return 游戏详细信息以及所有具有此请求映射模板的玩家:
{
"version": "2017-02-28",
"operation": "Query",
"query" : {
"expression" : "pk = :pk",
"expressionValues" : {
":pk": { "S": "$ctx.arguments.pk" }
}
}
}
以上查询returns 5 个项目(4 个玩家和游戏元数据)。然后我使用了这样的响应映射模板:
#set($game = {})
#set($players = [])
#foreach($item in $ctx.result.items)
#if($util.matches('meta_\d*', $item.sk))
## main game object
#set($game = $item)
#else
## player
$util.qr($players.add($item))
#end
#end
$util.qr($game.put("players", $players))
$util.toJson($game)
现在我有一个 DynamoDB 的单一查询,没有 lambda 解析器...很漂亮。
我有一个 DynamoDB table,它有 Games
和 Players
。我目前有以下适用于我的 AppSync getGame 查询的 Lambda 解析器。问题是,是否可以使用执行相同操作的速度模板编写 DynamoDB 解析器,这样我就可以避免 lambda 调用。
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event) => {
let result = null;
let params;
switch(event.field) {
case "getGame":
const id = event.arguments.id;
if (!id) {
throw new Error('Missing game id');
};
params = {
TableName: 'games',
KeyConditionExpression: 'pk = :pk AND sk = :sk',
ExpressionAttributeValues: {
':pk': 'game',
':sk': `meta_${id}`
}
};
const game = (await docClient.query(params).promise()).Items[0];
// get players
const gameKey = `game_${game.sk.split('_')[1]}_${game.sk.split('_')[2]}`;
params = {
TableName: 'games',
KeyConditionExpression: 'pk = :pk AND begins_with(sk, :sk)',
ExpressionAttributeValues: {
':pk': gameKey,
':sk': 'player_'
}
};
game.players = (await docClient.query(params).promise()).Items;
result = game;
break;
}
return result;
};
结果看起来像
{
"gsipk": "NEW_OPEN",
"sk": "meta_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"gsisk": "level_1_players_4",
"pk": "game",
"players": [
{
"gsipk": "player_3a7bb19c-0ccd-42df-a606-acd8b1f5e288",
"gsisk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"points": 0,
"num": 4,
"place": null,
"sk": "player_3a7bb19c-0ccd-42df-a606-acd8b1f5e288",
"pieces": [],
"wilds": 0,
"pk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"color": "gold",
"pows": 0
},
{
"gsipk": "player_96b772b1-4127-43da-b550-029d5c632675",
"gsisk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"points": 0,
"num": 2,
"place": null,
"sk": "player_96b772b1-4127-43da-b550-029d5c632675",
"pieces": [],
"wilds": 0,
"pk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"color": "blue",
"pows": 0
},
{
"gsipk": "player_9d30c675-930f-401b-ac5f-8db32bb2acb8",
"gsisk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"points": 0,
"num": 3,
"place": null,
"sk": "player_9d30c675-930f-401b-ac5f-8db32bb2acb8",
"pieces": [],
"wilds": 0,
"pk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"color": "green",
"pows": 0
},
{
"gsipk": "player_ab179ad1-a160-44f8-b438-0e93385b6c47",
"gsisk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"points": 0,
"num": 1,
"place": null,
"sk": "player_ab179ad1-a160-44f8-b438-0e93385b6c47",
"pieces": [],
"wilds": 0,
"pk": "game_1578241126110_35660fcc-3cde-4d30-9ebd-09abba1aedf7",
"color": "red",
"pows": 0
}
]
}
除非您重新映射数据以便能够在一个请求中获取所有项目,否则您将需要 Pipeline resolvers.。总而言之,管道是一些解析器,它们被包裹在 before/after 模板中。
在您的情况下,这些 before/after 模板并未真正使用,因此基本设置为:
在模板之前(不需要任何东西,所以一个空的 json 就可以了)
{}
模板之后(传递之前调用的结果)
$util.toJson($ctx.result)
那么您将拥有 2 个 DynamoDB 解析器。这些与您之前可能完成的其他 DynamoDB 解析器相同,除了在第二个中,为了访问第一个 DynamoDB 解析器结果,您将使用 $ctx.prev.result
。因此,假设您在第一次调用的响应中将游戏 ID 传递为:
{
"game_id": "$ctx.result.get('theGameId')",
...
}
然后可以在第二个请求模板中访问 $ctx.prev.result.game_id
。您也可以使用存储代替 - $ctx.stash.put()
和 $ctx.prev.get()
。如果您需要在 BEFORE 请求中执行某些操作(我们现在留空的第一个请求)并将其传递给整个解析器,则存储很有用。
好的,感谢@cyberwombat 的评论:
Unless you remap your data to be able to fetch all items in one request
我想通了。首先,我不得不重构我的 table 一点。我将主键(哈希)更改为 game_<uuid>
,然后使用 meta_<timestamp>
等排序键(范围)引用游戏详细信息,并使用 player_<uuid>
等排序键引用玩家。
一旦我这样做了,我就能够使用这个解析器来查询和 return 游戏详细信息以及所有具有此请求映射模板的玩家:
{
"version": "2017-02-28",
"operation": "Query",
"query" : {
"expression" : "pk = :pk",
"expressionValues" : {
":pk": { "S": "$ctx.arguments.pk" }
}
}
}
以上查询returns 5 个项目(4 个玩家和游戏元数据)。然后我使用了这样的响应映射模板:
#set($game = {})
#set($players = [])
#foreach($item in $ctx.result.items)
#if($util.matches('meta_\d*', $item.sk))
## main game object
#set($game = $item)
#else
## player
$util.qr($players.add($item))
#end
#end
$util.qr($game.put("players", $players))
$util.toJson($game)
现在我有一个 DynamoDB 的单一查询,没有 lambda 解析器...很漂亮。