如何在Dynamodb中有效查询嵌套属性?
我有一个如下文档结构,它允许我将相关信息存储在文档中(而不是引用它)。
存储嵌套在课程中的研讨会是有意义的,因为它们可能会在课程中被查询(它们都是课程特定的,即课程有很多研讨会,研讨会属于课程)。
在我迁移的CouchDB中,我可以编写一个View,它会为查询投射一些嵌套属性。我知道我不能将任何不是顶级属性的东西投射到dynamodb二级索引中,所以这种方法似乎不起作用。
这让我回到了这个问题:如果我不能将它们用作索引中的键,我如何在不扫描的情况下有效地查询嵌套属性?
例如,如果我想获得纳尔逊曼德拉剧院的平均出勤率,我如何在所有位于“纳尔逊曼德拉剧院”的研讨会中查询registrations
和attendees
的值。不求助于扫描?
{
“course_id”: “ABC-1234567”,
“course_name”: “Statistics 101”,
“tutors”: [“Cognito-sub-1”, “Cognito-sub-2”],
“seminars”: [
{
“seminar_id”: “XXXYYY-12345”,
“epoch_time”: “123456789”,
“duration”: “5400”,
“location”: “Nelson Mandela Theatre”,
“name”: “How to lie with statistics”,
“registrations”: “92”,
“attendees”: “61”
},
{
“seminar_id”: “BBBCCC-44444”,
“epoch_time”: “155555555”,
“duration”: “5400”,
“location”: “Nelson Mandela Theatre”,
“name”: “Statistical significance for dog owners”,
“registrations”: “244”,
“attendees”: “240”
},
{
“seminar_id”: “XXXAAA-54321”,
“epoch_time”: “223456789”,
“duration”: “4000”,
“location”: “Starbucks”,
“name”: “Is feral cat population growth a leading indicator for the S&P 500?”,
“registrations”: “40”
}
]
}
{
“course_id”: “CJX-5553389”,
“course_name”: “Cat Health 101”,
“tutors”: [“Cognito-sub-4”, “Cognito-sub-9”],
“seminars”: [
{
“seminar_id”: “TTRHJK-43278”,
“epoch_time”: “123456789”,
“duration”: “5400”,
“location”: “Catwoman Hall”,
“name”: “Emotional support octopi for cats”,
“registrations”: “88”,
“attendees”: “87”
},
{
“seminar_id”: “BBBCCC-44444”,
“epoch_time”: “123666789”,
“duration”: “5400”,
“location”: “Nelson Mandela Theatre”,
“name”: “Statistical significance for cat owners”,
“registrations”: “44”,
“attendees”: “44”
}
]
}
答案 0 :(得分:6)
无法为嵌套属性(即Dynamodb中的文档数据类型)创建索引。
文档类型 - 文档类型可以表示复杂的结构 使用嵌套属性 - 例如您可以在JSON文档中找到的属性。该 文档类型是列表和地图。
查询Api: -
查询操作仅搜索主键属性值,并支持关键属性值的比较运算符子集,以优化搜索过程。
扫描API: -
扫描操作扫描整个表格。您可以指定过滤器以应用于结果,以在完整扫描后优化返回给您的值。
为了使用Query API
,需要哈希键值。 OP没有任何散列键值可用的信息。根据OP,数据需要通过Dynamodb location
数据类型内的List
属性进行查询。现在,选择是看GSI。
请详细了解GSI。其中一条规则是GSI只能使用顶级属性创建。因此,该位置不能用于创建索引。
因此,为了使用查询API而创建GSI也已被排除。
索引键属性可以包含任何顶级字符串Number, 或基表中的二进制属性;其他标量类型,文档 不允许使用类型和集合类型。
由于上述原因,我们无法使用查询API来获取基于location
属性的数据,假设哈希键值不可用。
如果哈希键值可用,FilterExpression
可用于过滤数据。过滤复杂列表数据类型中存在的数据的唯一方法是CONTAINS
函数。为了使用CONTAINS
函数,事件中的所有属性都需要与数据匹配(即seminar_id,location,duration和所有其他属性)。因此,绝对不可能使用当前数据模型来满足OP中提到的用例。
建议的替代解决方案: -
如下所述对数据结构进行重新建模可能是解决问题的一种方法。绝对没有其他解决方案可以使用Query API来完成用例。
主要表: -
课程ID - 哈希键
seminar_id - 排序键
GSI: -
研讨会地点 - 哈希键
课程ID - 排序键
在DynamoDB表中,每个键值必须是唯一的。但是,关键 global secondary index中的值不需要是唯一的。
现在,您可以使用GSI上的查询API来获取Seminar location
的数据等于Nelson Mandela Theatre
。如果您知道值,则可以在查询api中使用课程ID。查询api可能会在结果集中提供多个项目。如果您希望根据某些非关键属性进一步过滤数据,则可以使用FilterExpression
。
答案 1 :(得分:0)
您可以做一件事以使其在Scan上运行 以stringify格式存储对象,例如 { “ language”:“ [{\” language \“:\” Male \“,\”熟练程度“:\”女性\“}]”“ }'' 然后可以执行扫描操作 语言: { 包含:“男” }
在客户端,您可以执行JSON.parse(language)
答案 2 :(得分:0)
我还没有使用DynamoDB的经验,但是因为我打算在下一个项目中使用它,所以开始研究它。
据我从AWS文档中了解的,您的问题的答案是:无法高效地查询嵌套属性。
着眼Best Practices,特别是Best Practices for Using Secondary Indexes in DynamoDB,可以理解正确的方法应该在与here相同的分区键下使用不同的线型。然后在相同的course_id下,您将拥有一个通用的排序键(sk)。然后,第一个寄存器将带有课程数据的sk ='Details',然后是其他寄存器,例如“ seminar-1”及其数据,依此类推。 然后,您要设置研讨会的属性,并将其作为SGI(二级全球索引)进行查询,但要记住,每个表只能包含5个SGI。
希望有帮助。
答案 3 :(得分:0)
这是一个来自here的示例,其中使用了一个过滤器表达式,它带有扫描操作,但也许您可以对查询应用类似的内容而不是扫描(看看API ):
{
"TableName": "MyTable",
"FilterExpression": "#k_Compatible.#k_RAM = :v_Compatible_RAM",
"ExpressionAttributeNames": {
"#k_Compatible": "Compatible",
"#k_RAM": "RAM"
},
"ExpressionAttributeValues": {
":v_Compatible_RAM": "RAM1"
}
}
答案 4 :(得分:0)
您可以使用document paths来过滤值。使用workshops.location作为文档路径。