如何查询 DynamoDB 按列表中的值过滤

How to query DynamoDB filtering by value in a list

数据库中有三项:

[
  {
    "year": 2013,
    "info": {
      "genres": ["Action", "Biography"]
    }
  },
  {
    "year": 2013,
    "info": {
      "genres": ["Crime", "Drama", "Thriller"]
    }
  },
  {
    "year": 2013,
    "info": {
      "genres": ["Action", "Adventure", "Sci-Fi", "Thriller"]

    }
  }
]

由于 year 属性是 table 的主键,我可以继续使用 FilterExpression 来匹配准确的 list["Action", "Biography"]:

var params = {
    TableName : TABLE_NAME,
    KeyConditionExpression: "#yr = :yyyy",
    FilterExpression: "info.genres = :genres",
    ExpressionAttributeNames:{
        "#yr": "year"
    },
    ExpressionAttributeValues: {
        ":yyyy": 2013,
        ":genres": ["Action", "Biography"]
    }     
};
var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();


let promise = docClient.query(params).promise();
promise.then(res => {
console.log("res:", res);
})

与其匹配整个列表 ["Action", "Biography"],我宁愿只查询 return 那些 table 项目,这些项目在存储在项目列表中的列表中包含字符串“传记” info.genres 字段。我想知道这是否可能使用 DynamoDB query API?

稍后编辑。

工作解决方案(感谢 Balu)是使用 QueryFilter contains 比较运算符:

var params = {
    TableName: TABLE_NAME,
    Limit: 20,
    KeyConditionExpression: "id = :yyyy",
    FilterExpression: `contains(info.genres , :qqqq)`,
    ExpressionAttributeValues: {
      ":qqqq": { S: "Biography" },
      ":yyyy": { N: 2013 },
    },
  }

let promise = docClient.query(params).promise();
promise.then(res => {
console.log("res:", res);
})

简答,没有。 DDB 允许存储 key:val 对,因此您要查询的元素应该是顶部元素。

长答案,是的。但是,它正在使用扫描。老实说,就 RCU 消耗而言,我认为查询和扫描之间没有太大区别。您可以使用 Limit 参数来限制 RCU 在单个网络调用中的使用。

如果我们到现在还不错,你可以用Document Paths in your Filter Expression to achieve what you're trying to do. See this stack overflow post, and this github例子。

但是,请注意这是一个扫描操作,而不是一个查询,并且它可能会非常昂贵,因为它不会使用任何索引并且会遍历每个table.

中的文档

最好将这些属性拉出到顶级文档中,并使用二级索引进行相应查询。

我们可以在过滤器表达式中使用 contains 而不是 =

所以,"info.genres = :genres"可以改成contains(info.genres , :gnOne)

AWS 仍将查询分区键,在应用过滤器之前在单个查询中提取最多 1 MB 的数据。因此,无论是否使用过滤器表达式,我们都会对相同的 RCU 收费,但返回给客户端的数据量将受到限制,因此,仍然有用。

const dynamodb = new AWS.DynamoDB();
dynamodb.query(
  {
    TableName: "my-test-table",
    Limit: 20,
    KeyConditionExpression: "id = :yyyy",
    FilterExpression: `contains(info.genres , :gnOne)`,
    ExpressionAttributeValues: {
      ":gnOne": { S: "Biography" },
      ":yyyy": { S: "2020" },
    },
  },
  function (err, data) {
    if (err) console.error(err);
    else console.log("dynamodb scan succeeded:", JSON.stringify(data, null, 2));
  }
);