如何使用非主键字段查询DynamoDB?

20

我在我的DynamoDB表中有以下数据。

在这里输入图片描述

这是我的代码:

const userStatusParams = {
        TableName: process.env.USERSTATUS_TABLE,
        KeyConditionExpression: "loggedIn = :loggedIn",
        ExpressionAttributeValues: {
          ":loggedIn": true
        }
      };
      var usersResult;
      try {
        usersResult = await dynamoDbLib.call("query", userStatusParams);
        console.log(usersResult);
      }catch (e) {
        console.log("Error occurred querying for users belong to group.");
        console.log(e);
      }

亚马逊返回了这个错误:

{ ValidationException: Query condition missed key schema element: userId
    at Request.extractError ...

如何让它返回所有loggedIn == true的记录?

我的数据库目前是通过我的serverless.yml配置结构化的。

phoneNumberTable: #This table is used to track phone numbers used in the system.
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:custom.phoneNumberTable}
        AttributeDefinitions: #UserID in this case will be created once and constantly updated as it changes with status regarding the user.
          - AttributeName: phoneNumber
            AttributeType: S
        KeySchema:
          - AttributeName: phoneNumber
            KeyType: HASH
        ProvisionedThroughput:
            ReadCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.pstage}}
            WriteCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.pstage}}

我通过其他答案进行了一些研究,但无法解决我的情况。在其他答案中,他们使用了排序键,但我这里没有使用排序键。

我研究了一下其他回答,但无法解决我的问题。在其他回答中,他们使用了排序键,但我在这里没有使用排序键。

如果您正在执行“查询”操作,则必须传递主键,而在您的情况下,该主键为“userId”。 - Prakash Sharma
你是指电话号码吗? - Joseph Astrahan
无论如何,在执行查询时我都没有主键可用。 - Joseph Astrahan
1
如果您想获取所有 logged in = true 的字段,则必须使用 filterExpression 进行 scan - Prakash Sharma
我在这里创建了一个修订版的问题,以进一步解决我的问题,https://dev59.com/26fja4cB1Zd3GeqPrzCC - Joseph Astrahan
3个回答

19

如果您在执行query操作,则必须传递主键,而在您的情况下主键是userId。如果您没有primaryKey,并且想要所有logged in = true的字段,则可以使用以下filterExpression执行scan操作。

const userStatusParams = {
        TableName: process.env.USERSTATUS_TABLE,
        FilterExpression: 'loggedIn = :loggedIn',
        ExpressionAttributeValues: {
          ":loggedIn": true
        }
      };
      var usersResult;
      try {
        // Do scan
        usersResult = await dynamoDbLib.call("scan", userStatusParams);
        console.log(usersResult);
      }catch (e) {
        console.log("Error occurred querying for users belong to group.");
        console.log(e);
      }

更新:由于scan操作的效率较低,解决这个问题的另一种方法是创建一个具有主键为loggedInGSI。但是这里的问题是您无法将任何具有boolean数据类型的字段作为主键。它必须是number、string、binary。因此,要创建一个gsi,您需要在loggedIn字段中存储接受的数据类型,而不是boolean

尽管我不确定对于包含数千条记录的表格会产生多少性能影响,但gsi的好处在于,即使在未来发现某些性能影响,您也可以随时在现有表格上创建它们。此外,在表格上可以创建的gsi的数量限制为5。所以要明智地利用gsi


所以在我的情况下,由于用户可能会增长到一千多个,我注意到其他用户建议使用二级索引。在这种情况下,扫描仍然更好吗? - Joseph Astrahan
@JosephAstrahan 毫无疑问,“scan”是昂贵的。请查看更新后的答案。如果您可以存储“number/string”来表示“loggedIn”字段,那么就可以使用它了 :) - Prakash Sharma
谢谢,这个答案给了我很多灵活性和选择。 - Joseph Astrahan
你知道如何在字符串集上进行过滤吗?比如按组进行过滤,只显示属于默认组的结果? - Joseph Astrahan
已经找到解决方案,对于其他人来说,代码如下:FilterExpression: "loggedIn = :loggedIn and #s = :status and contains(#g,:group) ",当然还要添加以下代码:ExpressionAttributeNames: {"#s": "status","#g" : "group"}。我不得不这样做是因为DynamoDB中的status和group是保留关键词。 - Joseph Astrahan

4

Scan操作始终会扫描整个表格或次要索引,然后过滤出值以提供所需的结果,实际上增加了从结果集中删除数据的额外步骤。如有可能,请避免在带有许多结果的过滤器的大型表格或索引上使用Scan操作。

阅读更多

您应该使用全局二级索引!

AWS控制台> DynamoDb> 您的表格的选项卡索引> 创建索引>

primary key - loggedIn
secondary key - userId
projected attributes - all

我们需要添加次要键来创建唯一的配对。不要使用索引名称(loggedIn),因为loggedIn应该是唯一的。然后,您可以使用主键(loggedIn)的查询方法。

这里我实际上要查询4个值:登录、组、优先级和状态以及类型。这张表可能不会超过一千条记录。 - Joseph Astrahan
我在这里创建了一个问题来解释这个问题,https://dev59.com/26fja4cB1Zd3GeqPrzCC - Joseph Astrahan
我已经为你的问题点赞了。我不确定使用DynamoDB是否可能。我建议在获取所有数据后,在你的Lambda中过滤数据。 - Dmitry Grinko
你知道怎么在扫描中获取组字符串集的访问权限吗? - Joseph Astrahan
我正在使用documentClient http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#scan-property - Dmitry Grinko
弄明白了,对于其他人来说是这样的,FilterExpression: "loggedIn = :loggedIn and #s = :status and contains(#g,:group) ",当然还要添加这个,ExpressionAttributeNames: {"#s": "状态","#g" : "组"}. 我不得不为状态和组这两个词在DynamoDB中是保留关键字而这样做。 - Joseph Astrahan

4
为了查询DynamoDB表,您只能查询作为主键或索引的一部分的属性。
主键可以是以下之一:
1. 分区/哈希键,或 2. 分区/哈希键和排序/范围键
除了主键之外,您还可以创建两种类型的索引:
1. 本地辅助索引,其中使用相同的分区键但具有不同的排序键。 2. 全局辅助索引,其中分区键和排序键均不同。
为了查询loggedIn记录,您需要将此属性包含在您的主键中,或添加包括loggedIn属性的本地或全局辅助索引。请注意,HTML标记已保留。

1
这个回答是不正确的,DynamoDB 允许在非索引属性上进行搜索。这种搜索被称为扫描。使用索引属性进行搜索称为查询。 - F_SO_K
2
扫描不等于搜索。 - Eyal Ch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接