正如之前模块中所述,您应该针对 DynamoDB 表接收的请求数量进行优化。此外我们还提到,关系数据库具有联接,而 DynamoDB 没有。作为替代,您可以设计表以允许您的请求中具有类似联接的行为。
在此步骤中,我们会在单个请求中检索多种实体类型。在游戏中,我们有时需要获取有关游戏会话的详细信息。这些详细信息包括有关游戏本身的信息(例如开始时间、结束时间、放置者)以及有关参与游戏的用户的详细信息。
该请求跨两种实体类型:Game 实体和 UserGameMapping 实体。但是,这并不意味着我们需要提出多个请求。
在您下载的代码中,可在 application/ 目录中找到 fetch_game_and_players.py 脚本。该脚本展示了如何构造代码以实现在单个请求中一并检索游戏的 Game 实体和 UserGameMapping 实体。
fetch_game_and_players.py 脚本的代码组成情况如下。
import boto3
from entities import Game, UserGameMapping
dynamodb = boto3.client('dynamodb')
GAME_ID = "3d4285f0-e52b-401a-a59b-112b38c4a26b"
def fetch_game_and_users(game_id):
resp = dynamodb.query(
TableName='battle-royale',
KeyConditionExpression="PK = :pk AND SK BETWEEN :metadata AND :users",
ExpressionAttributeValues={
":pk": { "S": "GAME#{}".format(game_id) },
":metadata": { "S": "#METADATA#{}".format(game_id) },
":users": { "S": "USER$" },
},
ScanIndexForward=True
)
game = Game(resp['Items'][0])
game.users = [UserGameMapping(item) for item in resp['Items'][1:]]
return game
game = fetch_game_and_users(GAME_ID)
print(game)
for user in game.users:
print(user)
在此脚本的开头,我们导入 Boto 3 库和一些简单的类,用来表示应用程序代码中的对象。您可以在 application/entities.py 文件中查看这些实体的定义。
脚本的实际工作发生在已在模块中定义的 fetch_game_and_users 函数。该函数类似于您在应用程序中定义的函数,供需要此数据的所有终端节点使用。
fetch_game_and_users 函数可以执行一些操作。首先,它向 DynamoDB 发出 Query 请求。该 Query 使用 PK 作为 GAME#<GameId>。然后,它请求排序键位于 #METADATA#<GameId> 和 USER$ 之间的所有实体。这一步将获取排序键为 #METADATA#<GameId> 的 Game 实体,以及键以 USER# 开头的所有 UserGameMappings 实体。字符串类型的排序键按 ASCII 字符代码的顺序进行排序。在 ASCII 中,美元符号 ($) 的位置在井字符号 (#) 之后,因此可确保我们能够在 UserGameMapping 实体中获取所有映射。
收到响应后,我们要将数据实体组装到应用程序已知的对象中。我们知道返回的第一个实体是 Game 实体,因此从该实体创建一个 Game 对象。对于其余实体,我们为每个实体创建一个 UserGameMapping 对象,然后将用户数组附加到 Game 对象。
脚本的末尾会展示该函数的使用情况,然后打印生成的对象。您可以使用以下命令在终端中运行该脚本。
该脚本应将 Game 对象和所有 UserGameMapping 对象打印到控制台。
Game<3d4285f0-e52b-401a-a59b-112b38c4a26b -- Green Grasslands>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- branchmichael>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- deanmcclure>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- emccoy>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- emma83>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- iherrera>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- jeremyjohnson>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- lisabaker>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- maryharris>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- mayrebecca>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- meghanhernandez>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- nruiz>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- pboyd>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- richardbowman>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- roberthill>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- robertwood>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- victoriapatrick>
UserGameMapping<3d4285f0-e52b-401a-a59b-112b38c4a26b -- waltervargas>
该脚本会展示如何在单个 DynamoDB 请求中对表进行建模,以及如何编写查询以检索多种实体类型。在关系数据库中,您可以使用联接在单个请求中从不同的表中检索多种实体类型。使用 DynamoDB,您可以对数据进行专门建模,以便让您应一起访问的实体在单个表中彼此相邻。这种方法无需使用典型关系数据库中的联接,并能够在您扩展应用程序时保持高性能。