我有这样的物品
{
"date": "2019-10-05",
"id": "2",
"serviceId": "1",
"time": {
"endTime": "1300",
"startTime": "1330"
}
}
现在,我的设计方式如下:
primary key --> id
Global secondary index --> primary key : serviceId
--> sort key : date
以我目前的设计方式,
* I can query the id
* I can query serviceId and range of date
我希望能够进行查询,以便可以在其中检索所有项目
* serviceId = 1 AND
* date = "yyyy-mm-dd" AND
* time = {
"endTime": "1300",
"startTime": "1330"
}
我仍然希望能够根据先前的2个条件进行查询(按ID查询,并按serviceId和rangeOfDate查询
有没有办法做到这一点?我在想的一种方法是创建一个新字段并将其用作索引,例如:合并所有数据,以便CombineField:“ 1_yyyy-mm-dd_1300_1330
将其作为全局二级索引的主键,然后像这样查询它。
我只是不确定这是这样做的方法,还是有更好或最佳实践的方法?
谢谢
是的,您建议的解决方案(添加一个新字段,该字段是字段的组合并在其上定义了GSI)是实现此目的的标准方法。您需要确保用于连接的字符是唯一的,即,它不能出现在您组合的任何单个字段中。
您可以使用FilterExpression或复合排序键。
在这里,您可以通过指定'serviceId'和'date',然后在'FilterExpression'中指定time.startTime和time.endTime,从您描述的GSI中检索项目。使用boto3的示例Python代码如下:
response = table.query(
KeyConditionExpression=Key('serviceId').eq(1) & Key('date').eq("2019-10-05"),
FilterExpression=Attr(time.endTime).eq('1300') & Attr('time.startTime').eq('1330')
)
此方法的缺点是,将读取所有使用排序键指定的项目,然后才对结果进行过滤。因此,将根据排序键中指定的费用向您收费。
例如:如果1000个项目的'serviceId'为1,'date'为'2019-10-05',但是只有10个项目的'time.startTime'为1330,那么即使读取1000个项目,您仍然要付费尽管在应用FilterExpression之后将仅返回10个项目。
我相信这是您在问题中提到的方法。在这里,您需要将一个属性设置为
'yyyy-mm-dd_startTime_endTime'
并将其用作GSI中的排序键。现在您的项目将如下所示:
{ "date": "2019-10-05",
"id": "2",
"serviceId": "1",
"time": {
"endTime": "1300",
"startTime": "1330"
}
"date_time":"2019-10-05_1330_1300"
}
您的GSI将以“ serviceId”作为分区键,并以“ date_time”作为排序键。现在,您可以查询日期范围为:
response = table.query(
KeyConditionExpression=Key('serviceId').eq(1) & Key('date').between('2019-07-05','2019-10-05')
)
对于指定日期,开始和结束时间的查询,您可以查询为:
response = table.query(
KeyConditionExpression=Key('serviceId').eq(1) & Key('date').eq('2019-10-05_1330_1300')
)
如果您同时需要一定范围的日期以及开始和结束时间,则此方法将无效。您将无法查询包含特定开始和结束时间的特定日期范围内的项目。在这种情况下,您将必须使用FilterExpression。