我对 Dynamodb 和 NoSQL 世界真的很陌生。我正在练习 AWS 的 GSI
和 LSI
。我正在使用无服务器框架。我将我的处理程序拆分为多个 lambda 函数。我想创建我的数据,在那里我可以看到所有餐馆以及他们的价格是什么类型的啤酒。另外我想查询所有没有价格的啤酒。我成功创建了餐厅,它的分区键是 id
。我可以获得所有餐厅数据。但我坚持啤酒逻辑。我为这样的啤酒创建了 api 端点 restaurant/{id}/createBeers
,当我提出发布请求时,我收到错误 "message": "One or more parameter values were invalid: Missing the key id in the item"
,因为它要求提供餐厅的 ID。我找不到可以添加餐厅 ID 来创建啤酒的逻辑,以及如何免费获得所有啤酒。
餐厅是一对多的。啤酒是多对多的(同名不同价格基于餐厅)。这就是我想要实现的目标。
[
{
"id": 1,
"name": "restaurent 1",
"beers": {
"tap-beers": [{
"name": "beer 1",
"price": "2$"
},
{
"name": "beer 2",
"price": "2$"
}
],
"bottle-beers": [{
"name": "beer 3",
"price": "2$"
},
{
"name": "beer 4",
"price": "2$"
}
]
}
},
{
"id": 2,
"name": "restaurent 2",
"beers": {
"tap-beers": [{
"name": "beer 1",
"price": "3$"
},
{
"name": "beer 2",
"price": "3$"
}
],
"bottle-beers": [{
"name": "beer 3",
"price": "4$"
},
{
"name": "beer 4",
"price": "6$"
}
]
}
}
]
这就是我想要得到桌上所有啤酒的方式
[
{
"beername": "beer 1"
},
{
"beername": "beer 2"
},
{
"beername": "beer 3"
},
{
"beername": "beer 4"
}
]
这是我的餐厅
const dynamoDb = new AWS.DynamoDB.DocumentClient();
module.exports.createRestaurant = async event => {
const resquestBody = JSON.parse(event.body);
const params = {
TableName: "table name",
Item: {
id: uuid.v1(),
name: resquestBody.name,
beers: [] // in here I will add beers when I can create a beer my post method path
// is restaurant/{id}/createBeers
}
}
try {
await dynamoDb.put(params).promise();
return {
statusCode: 200,
body: JSON.stringify(resquestBody),
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify(error),
};
}
};
这是创建啤酒处理程序
const dynamoDb = new AWS.DynamoDB.DocumentClient();
module.exports.createBeers = async event => {
const requestBody = JSON.parse(event.body);
const params = {
TableName: "table name",
Item: {
beer_name: requestBody.beer_name,
beer_type: requestBody.beer_type,
beer_price: requestBody.beer_price
}
};
try {
await dynamoDb.put(params).promise();
return {
statusCode: 200,
body: JSON.stringify(requestBody),
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify(error),
};
}
};
这是我的GSI
免费获得所有啤酒
module.exports.getBeers = async event => {
const params = {
TableName: "beer",
IndexName: "beers",
KeyConditionExpression: "beer_name = :beer_name",
ExpressionAttributeValues: {
":beer_name": "beer_name"
},
Limit: 1
}
try {
let data = await dynamoDb.query(params).promise();
return {
statusCode: 200,
body: JSON.stringify(data.Items),
};
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify(error),
};
}
}
这是我的无服务器 yml 文件
functions:
createRestaurant:
handler: handlers/createRestaurant.createRestaurant
events:
- http:
path: restaurant
method: post
cors: true
getRestaurants:
handler: handlers/getRestaurants.getRestaurants
events:
- http:
path: restaurant/all
method: get
cors: true
createBeers:
handler: handlers/createBeers.createBeers
events:
- http:
path: restaurant/{id}/beers
method: post
cors: true
getBeers:
handler: handlers/getBeers.getBeers
events:
- http:
path: beers/all
method: get
cors: true
resources:
Resources:
table:
Type: "AWS::DynamoDB::Table"
DeletionPolicy: Retain
Properties:
AttributeDefinitions:
- AttributeName: id
AttributeType: S
- AttributeName: beer_name
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
GlobalSecondaryIndexes:
- IndexName: beers
KeySchema:
- AttributeName: beer_name
KeyType: HASH
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
TableName: "tableName"
答案 0 :(得分:2)
据我所知,您有两个实体:
每家餐厅可能有多种啤酒,每只熊要么是瓶装的,要么是自来水的,也有价格。
您想要启用这些访问模式:
我提出了一个带有全局二级索引 (GSI1) 的单个表,如下所示:
GSI1
查询 PK=RESTAURANTS
import typing
import boto3
import boto3.dynamodb.conditions as conditions
def get_all_restaurants() -> typing.List[dict]:
table = boto3.resource("dynamodb").Table("table-name")
response = table.query(
KeyConditionExpression=conditions.Key("GSI1PK").eq("RESTAURANTS"),
IndexName="GSI1"
)
return response["Items"]
PK=R<restaurant-id> and SK begins_with B
对主索引进行查询(您可以将 B
替换为 B-TP
beers 或 B-BB
表示所有瓶装啤酒。去掉有关餐厅的所有信息的 SK 条件。)import typing
import boto3
import boto3.dynamodb.conditions as conditions
def get_beers_in_restaurant(restaurant_id: str) -> typing.List[dict]:
table = boto3.resource("dynamodb").Table("table-name")
response = table.query(
KeyConditionExpression=conditions.Key("PK").eq(f"R#{restaurant_id}") \
& conditions.Key("SK").begins_with("B-")
)
return response["Items"]
def get_tap_beers_in_restaurant(restaurant_id: str) -> typing.List[dict]:
table = boto3.resource("dynamodb").Table("table-name")
response = table.query(
KeyConditionExpression=conditions.Key("PK").eq(f"R#{restaurant_id}") \
& conditions.Key("SK").begins_with("B-TB")
)
return response["Items"]
def get_bottled_beers_in_restaurant(restaurant_id: str) -> typing.List[dict]:
table = boto3.resource("dynamodb").Table("table-name")
response = table.query(
KeyConditionExpression=conditions.Key("PK").eq(f"R#{restaurant_id}") \
& conditions.Key("SK").begins_with("B-BB")
)
return response["Items"]
GSI1
查询 PK=BEERS
。您将获得重复项,因此您需要删除这些客户端。import typing
import boto3
import boto3.dynamodb.conditions as conditions
def get_all_beers() -> typing.List[dict]:
table = boto3.resource("dynamodb").Table("data")
response = table.query(
KeyConditionExpression=conditions.Key("GSI1PK").eq("BEERS"),
IndexName="GSI1"
)
list_with_duplicates = [item["name"] for item in response["Items"]]
list_without_duplicates = list(set(list_with_duplicates))
return [{"beername": name} for name in list_without_duplicates]
当您现在向表中添加项目时,您必须考虑要创建的实体类型。
餐馆很简单,他们只需要一个 ID 和一个名字。根据这些信息,我们可以计算出关键属性:
import boto3
def create_restaurant(restaurant_id: str, name: str) -> None:
table = boto3.resource("dynamodb").Table("data")
item = {
"PK": f"R#{restaurant_id}",
"SK": "META",
"GSI1PK": "RESTAURANTS",
"GSI1SK": f"R#{restaurant_id}",
"type": "RESTAURANT",
"id": restaurant_id,
"name": name
}
table.put_item(
Item=item
)
啤酒总是属于一家餐厅,所以我们需要有它的 id - 它也总是有价格和名称。
import boto3
def create_beer_for_restaurant(restaurant_id: str, name: str, price: str, is_tap: bool):
table = boto3.resource("dynamodb").Table("data")
sk = f"B-TB#{name}" if is_tap else f"B-BB#{name}"
item = {
"PK": f"R#{restaurant_id}",
"SK": sk,
"GSI1PK": "BEERS",
"GSI1SK": f"B#{name}",
"name": name,
"price": price
}
table.put_item(
Item=item
)