如何按DynamoDB中的数组(或嵌套对象)中的元素进行过滤

时间:2018-04-30 01:18:32

标签: amazon-dynamodb dynamodb-queries

我的数据如下:

[
  {
    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
  }
]

当然不是吗?

2 个答案:

答案 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操作而不使用已弃用的QueryFilterFilterExpression: "contains(categories, :categoriesValue)"