简体   繁体   English

如何使用复合条件查询 DynamoDB GSI

[英]How to query DynamoDB GSI with compound conditions

I have a DynamoDB table called 'frank' with a single GSI.我有一个名为“frank”的 DynamoDB 表,只有一个 GSI。 The partition key is called PK, the sort key is called SK, the GSI partition key is called GSI1_PK and the GSI sort key is called GSI1_SK.分区键称为 PK,排序键称为 SK,GSI 分区键称为 GSI1_PK,GSI 排序键称为 GSI1_SK。 I have a single 'data' map storing the actual data.我有一个“数据”map 存储实际数据。

Populated with some test data it looks like this:填充了一些测试数据,它看起来像这样: 在此处输入图像描述

The GSI partition key and sort key map directly to the attributes with the same names within the table. GSI 分区键和排序键 map 直接指向表内的同名属性。

I can run a partiql query to grab the results that are shown in the image.我可以运行 partiql 查询来获取图像中显示的结果。 Here's the partiql code:这是 partiql 代码:

select PK, SK, GSI1_PK, GSI1_SK, data from "frank"."GSI1"
where 
("GSI1_PK"='tesla')
and 
(
 (  "GSI1_SK" >= 'A_VISITOR#2021-06-01-00-00-00-000' and  "GSI1_SK" <= 'A_VISITOR#2021-06-20-23-59-59-999' )
 or
 (  "GSI1_SK" >= 'B_INTERACTION#2021-06-01-00-00-00-000'  and   "GSI1_SK" <= 'B_INTERACTION#2021-06-20-23-59-59-999' )
)

Note how the partiql code references "GSI1_SK" multiple times.请注意 partiql 代码如何多次引用“GSI1_SK”。 The partiql query works, and returns the data shown in the image. partiql 查询有效,并返回图像中显示的数据。 All great so far.到目前为止一切都很好。

However, I now want to move this into a Lambda function. How do I structure a AWS.DynamoDB.DocumentClient query to do exactly what this partiql query is doing?但是,我现在想将其移至 Lambda function。如何构建 AWS.DynamoDB.DocumentClient 查询以准确执行此 partiql 查询的操作?

I can get this to work in my Lambda function:我可以在我的 Lambda function 中使用它:

const visitorStart="A_VISITOR#2021-06-01-00-00-00-000";
        const visitorEnd="A_VISITOR#2021-06-20-23-59-59-999";
        
        var params = {
          TableName: "frank",
          IndexName: "GSI1",
          KeyConditionExpression: "#GSI1_PK=:tmn AND #GSI1_SK BETWEEN :visitorStart AND :visitorEnd",
          ExpressionAttributeNames :{  "#GSI1_PK":"GSI1_PK", "#GSI1_SK":"GSI1_SK" },
          ExpressionAttributeValues: {
            ":tmn": lowerCaseTeamName,
            ":visitorStart": visitorStart,
            ":visitorEnd": visitorEnd
          }
        };
        
        const data = await documentClient.query(params).promise();
        console.log(data); 

But as soon as I try a more complex compound condition I get this error:但是,一旦我尝试更复杂的复合条件,我就会收到此错误:

ValidationException: Invalid operator used in KeyConditionExpression: OR

Here is the more complex attempt:这是更复杂的尝试:

const visitorStart="A_VISITOR#2021-06-01-00-00-00-000";
        const visitorEnd="A_VISITOR#2021-06-20-23-59-59-999";
        const interactionStart="B_INTERACTION#2021-06-01-00-00-00-000";
        const interactionEnd="B_INTERACTION#2021-06-20-23-59-59-999";
        
        var params = {
          TableName: "frank",
          IndexName: "GSI1",
          KeyConditionExpression: "#GSI1_PK=:tmn AND (#GSI1_SK BETWEEN :visitorStart AND :visitorEnd OR #GSI1_SK BETWEEN :interactionStart AND :interactionEnd) ",
          ExpressionAttributeNames :{  "#GSI1_PK":"GSI1_PK", "#GSI1_SK":"GSI1_SK" },
          ExpressionAttributeValues: {
            ":tmn": lowerCaseTeamName,
            ":visitorStart": visitorStart,
            ":visitorEnd": visitorEnd,
            ":interactionStart": interactionStart,
            ":interactionEnd": interactionEnd
          }
        };
        
        const data = await documentClient.query(params).promise();
        console.log(data);  

The docs say that KeyConditionExpressions don't support 'OR'.文档说 KeyConditionExpressions 不支持“或”。 So, how do I replicate my more complex partiql query in Lambda using AWS.DynamoDB.DocumentClient?那么,如何使用 AWS.DynamoDB.DocumentClient 在 Lambda 中复制更复杂的 partiql 查询?

If you look at the documentation of PartiQL for DynamoDB they do warn you, that PartiQL has no scruples to use a full table scan to get you your data: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html#ql-reference.select.syntax如果您查看 PartiQL for DynamoDB 的文档,他们会警告您,PartiQL 会毫无顾忌地使用全表扫描来获取您的数据: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ ql-reference.select.html#ql-reference.select.syntax

To ensure that a SELECT statement does not result in a full table scan, the WHERE clause condition must specify a partition key.为确保 SELECT 语句不会导致全表扫描,WHERE 子句条件必须指定分区键。 Use the equality or IN operator.使用相等或 IN 运算符。

In those cases PartiQL would run a scan and use a FilterExpression to filter out the data.在这些情况下,PartiQL 将运行扫描并使用FilterExpression过滤掉数据。

Of course in your example you provided a partition key, so I'd assume that PartiQL would run a query with the partition key and a FilterExpression to apply the rest of the condition.当然,在您的示例中,您提供了分区键,因此我假设 PartiQL 将使用分区键和 FilterExpression 运行查询以应用条件的FilterExpression

You could replicate it that way, and depending on the size of your partitions this might work just fine.您可以那样复制它,并且根据分区的大小,这可能会很好地工作。 However, if the partition will grow beyond 1MB and most of the data would be filtered out, you'll need to deal with pagination even though you won't get any data.但是,如果分区增长超过 1MB 并且大部分数据将被过滤掉,那么即使您不会获得任何数据,您也需要处理分页。

Because of that I'd suggest you to simply split it up and run each or condition as a separate query, and merge the data on the client.因此,我建议您简单地将其拆分并将每个或条件作为单独的查询运行,然后在客户端合并数据。

Unfortunately, DynamoDB does not support multiple boolean operations in the KeyConditionExpression .遗憾的是,DynamoDB 不支持 KeyConditionExpression 中的多个KeyConditionExpression操作。 The partiql query you are executing is probably performing a full table scan to return the results.您正在执行的 partiql 查询可能正在执行全表扫描以返回结果。

If you want to replicate the partiql query using the DocumentClient, you could use the scan operation.如果要使用 DocumentClient 复制 partiql 查询,可以使用scan操作。 If you want to avoid using scan , you could perform two separate query operations and join the results in your application code.如果您想避免使用scan ,您可以执行两个单独的query操作并将结果加入您的应用程序代码中。

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

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