繁体   English   中英

如何按列表中的值查询 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属性作为表的主键,我可以提前 go 并使用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"]我宁愿进行查询以仅返回那些在存储在项目的info.genres字段中的列表中包含字符串 "Biography" 的表项目。 我想知道这是否可能使用 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 在单个网络调用中的使用。

如果到目前为止我们还不错,您可以在过滤器表达式中使用文档路径来实现您想要做的事情。 请参阅堆栈溢出帖子和github 示例。

但是,请注意,这是一个 Scan 操作,而不是一个查询,并且它可能会变得非常昂贵,因为它不会使用任何索引并且会遍历表中的每个文档。

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

我们可以在 Filter 表达式中使用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));
  }
);

也许我很疯狂,但如果不是安全问题,我最近会为这种事情发送一个 json 文件映射 id 到我想要搜索的字段并执行所有过滤客户端。 我只有长度小于 20,000 的列表,到目前为止没有发现性能问题,当然这不能扩展到大型列表。

当您真正知道您的密钥并且可以避免具有大量结果的扫描/查询时,Dynamodb 是如此便宜,这对于小型项目来说是不可抗拒的。 我知道这是 hacky 但一个非常“免费”的解决方案,可能只需为您的客户端下载添加 1-2MB。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM