我的数据如下:
[
{
orgId: "ABC",
categories: [
"music",
"dance"
]
},
{
orgId: "XYZ",
categories: [
"math",
"science",
"art"
]
},
...
]
我在orgId
上有主键,我想使用DynamoDB query
过滤并仅返回类别为“science”的项目。
(类别不需要是任何索引的一部分:我愿意接受额外的工作人员开销,前提是我可以在Dynamo本身内进行查询。)
我有一个时间的狄更斯得到这个工作。如果有帮助,我可以随时将categories
更改为嵌套对象吗?
但DynamoDB中的比较运算符如此受限,以至于无法按数组元素或嵌套对象进行过滤?
如果没有,这里有什么更好的方法?要将每个类别转换为自己的第一级属性,例如:
[
{
orgId: "XYZ",
category_math: true,
category_science: true
}
]
当然不是吗?
答案 0 :(得分:3)
var params = {
ExpressionAttributeValues: {
":orgIdValue": {
S: "XYZ"
},
":categoriesValue": {
S: "science"
}
},
KeyConditionExpression: "orgId = :orgIdValue",
FilterExpression : "categories CONTAINS :categoriesValue",
TableName: "MYTABLE"
};
dynamodb.query(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
CONTAINS:检查子序列或集合中的值。 AttributeValueList只能包含一个类型的AttributeValue元素 字符串,数字或二进制(不是集类型)。如果是目标属性 比较是String类型,然后运算符检查a 子串匹配。如果比较的目标属性是类型 二进制,然后运算符查找目标的子序列 匹配输入。 如果比较的目标属性是一个集合 (“SS”,“NS”或“BS”),如果找到,则运算符求值为true 与该组的任何成员完全匹配。支持CONTAINS 列表:评估“a CONTAINS b”时,“a”可以是列表;然而,“b” 不能是集合,地图或列表。
类别是顶级属性,您实际上没有任何嵌套属性。可以索引顶级标量属性。虽然类别是顶级的,但它不是标量属性(它是一个集合),因此您无法将其编入索引。
您可以使用FilterExpression缩小查询范围,也可以在列表中使用CONTAINS比较器。
答案 1 :(得分:2)
根据文档,上面发布的答案应该有效。但是当使用Node.JS AWS DynamoDB SDK的DocumentClient时,却没有。特别是,我试过了:
{
TableName: "site",
IndexName: "orgId-lastCaptured-index",
KeyConditionExpression: "orgId = :orgId",
FilterExpression: "categories CONTAINS :categoriesValue",
ExpressionAttributeValues: {
":orgId": orgId,
":categoriesValue": myVariable,
}
}
这导致以下错误:{ ValidationException: Invalid FilterExpression: Syntax error; token: "CONTAINS", near: "categories CONTAINS :categoriesValue"
我将查询调整为备用查询格式,如下所示:
{
TableName: "site",
IndexName: "orgId-lastCaptured-index",
KeyConditions: {
orgId: {
ComparisonOperator: "EQ",
AttributeValueList: [orgId],
},
},
QueryFilter: {
categories: {
ComparisonOperator: "CONTAINS",
AttributeValueList: [myVariable],
}
}
}
这按预期工作,过滤返回的结果,使categories
变量的元素与myVariable
匹配。
更新:您现在可以使用以下语法执行CONTAINS
操作而不使用已弃用的QueryFilter
:FilterExpression: "contains(categories, :categoriesValue)"