【问题标题】:How to filter by elements in an array (or nested object) in DynamoDB如何在 DynamoDB 中按数组(或嵌套对象)中的元素进行过滤
【发布时间】:2025-12-07 03:05:01
【问题描述】:

我的数据如下:

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

我在 orgId 上有主键,我想使用 DynamoDB query 过滤并仅返回类别为“科学”的项目。

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

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

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

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

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

确定不是?

【问题讨论】:

    标签: amazon-dynamodb dynamodb-queries


    【解决方案1】:
     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 类型的元素 字符串、数字或二进制(不是集合类型)。如果目标属性为 比较是字符串类型,然后操作员检查一个 子串匹配。如果比较的目标属性是类型 二进制,然后运算符查找目标的子序列 匹配输入。 如果比较的目标属性是一个集合 (“SS”、“NS”或“BS”),则如果找到,则运算符评估为真 与集合的任何成员完全匹配。包含支持 列表:评估“a CONTAINS b”时,“a”可以是列表;但是,“b” 不能是集合、地图或列表。

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

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

    【讨论】:

    • 谢谢。这应该工作,但无论出于何种原因它都没有。它返回Invalid FilterExpression: Syntax error; token: "CONTAINS"。但是,它使我找到了一个可行的解决方案(使用DocumentClient SDK):{ ... QueryFilter: { categories: { ComparisonOperator: "CONTAINS", AttributeValueList: [myCategoryVariable], } ... }
    【解决方案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 匹配的元素。

    更新:您现在可以在不使用已弃用的 QueryFilter 的情况下执行 CONTAINS 操作,语法如下:FilterExpression: "contains(categories, :categoriesValue)"

    【讨论】:

      最近更新 更多