4

我的数据如下:

[
  {
    orgId: "ABC",
    categories: [
      "music",
      "dance"
    ]
  },
  {
    orgId: "XYZ",
    categories: [
      "math",
      "science",
      "art"
    ]
  },
  ...
]

我有主键orgId,例如,我想使用 DynamoDBquery过滤并仅返回具有“科学”类别的项目。

(类别不需要是任何索引的一部分:我愿意接受额外的工作人员开销,前提是我可以在 Dynamo 本身内进行查询。)

我有一段时间让这个工作正常。categories如果有帮助,我可以很容易地更改为嵌套对象?

但是 DynamoDB 中的比较运算符非常有限,以至于似乎无法按数组元素或嵌套对象进行过滤?

如果没有,这里有什么更好的方法?将每个类别转化为自己的一级属性,例如:

[
  {
    orgId: "XYZ",
    category_math: true,
    category_science: true
  }
]

确定不是吗?

4

2 回答 2

7
 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 只能包含一个 String、Number 或 Binary 类型(不是集合类型)的 AttributeValue 元素。如果比较的目标属性是字符串类型,则运算符检查子字符串匹配。如果比较的目标属性是二进制类型,则运算符会查找与输入匹配的目标子序列。如果比较的目标属性是一个集合(“SS”、“NS”或“BS”),那么如果它找到与该集合的任何成员完全匹配的运算符,则它的计算结果为真。列表支持 CONTAINS:评估“a CONTAINS b”时,“a”可以是列表;但是,“b”不能是集合、映射或列表。

类别是顶级属性,您实际上没有任何嵌套属性。可以索引顶级标量属性。虽然类别是顶级的,但它不是一个标量属性(它是一个集合),所以你不能索引它。

您可以使用 FilterExpression 来缩小查询范围,并且可以在列表上使用 CONTAINS 比较器。

于 2018-04-30T08:25:43.200 回答
4

根据文档,上面发布的答案应该有效。但是当使用 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)"

于 2018-04-30T12:19:37.293 回答