Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 按优先级排序结果&;集团价值观及;然后过滤结果_Node.js_Amazon Web Services_Amazon Dynamodb_Serverless Framework - Fatal编程技术网

Node.js 按优先级排序结果&;集团价值观及;然后过滤结果

Node.js 按优先级排序结果&;集团价值观及;然后过滤结果,node.js,amazon-web-services,amazon-dynamodb,serverless-framework,Node.js,Amazon Web Services,Amazon Dynamodb,Serverless Framework,这是我的DynamoDB当前数据: 我的目标是创建一个查询,它过滤组集中的结果(类似于“Default”),然后按优先级排序,然后将结果过滤到loggedIn==true和status==idle的位置 在SQL中,它类似于 SELECT * FROM userstatustable WHERE group == "default" AND loggedIn == true AND status == "idle" ORDER BY priority DESC LIMIT 1

这是我的DynamoDB当前数据:

我的目标是创建一个查询,它过滤组集中的结果(类似于“Default”),然后按优先级排序,然后将结果过滤到loggedIn==true和status==idle的位置

在SQL中,它类似于

SELECT * 
FROM userstatustable 
WHERE group == "default" 
  AND loggedIn == true AND status == "idle" 
ORDER BY priority DESC 
LIMIT 1
我将如何创建查询来执行此操作

下面是DynamoDB表的serverless.yml文件描述

userStatusTable: #This table is used to track a users current status.
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:custom.userStatusTable}
        AttributeDefinitions: #UserID in this case will be created once and constantly updated as it changes with status regarding the user.
          - AttributeName: userId
            AttributeType: S
        KeySchema:
          - AttributeName: userId
            KeyType: HASH
        ProvisionedThroughput:
            ReadCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.pstage}}
            WriteCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.pstage}}
我尝试过的事情:

以下是我目前的代码:

 const userStatusParams = {
        TableName: process.env.USERSTATUS_TABLE,
        FilterExpression: "loggedIn = :loggedIn and #s = :status and contains(#g,:group) ",
        //Limit: 1,
        ExpressionAttributeValues: {
          ":loggedIn": true,
          ":status" : "idle",
          ":group" : "DEFAULT"
        },
        ExpressionAttributeNames: {"#s": "status","#g" : "group"}
      };
      var usersResult;
      try {
        usersResult = await dynamoDbLib.call("scan", userStatusParams);
        console.log(usersResult);
      }catch (e) {
        console.log("Error occurred querying for users belong to group.");
        console.log(e);
      }
这使用扫描,能够返回所有符合条件的结果。。。但是,它不会按优先级对结果进行降序排序


注意:status和group显然是保留关键字,因此我不得不使用
ExpressionAttributeNames
来解释这一点。还要注意,这个表最终将有数千个用户。

因此我找到了一个有趣的解决方案

这是我的新代码

const userStatusParams = {
        TableName: process.env.USERSTATUS_TABLE,
        IndexName:"typePriorityIndex",
        FilterExpression: "loggedIn = :loggedIn and #s = :status and contains(#g,:group) ",
        KeyConditionExpression: "#t = :type and priority >= :priority",
        Limit: 1,
        ExpressionAttributeValues: {
          ":loggedIn": true,
          ":status" : "idle",
          ":group" : "DEFAULT",
          ":priority" : 0,
          ":type" : "admin"
        },
        ExpressionAttributeNames: {"#s": "status","#g" : "group", "#t" : "type"}
      };
      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);
      }
注意IndexName的使用:“typePriorityIndex”,这里的诀窍是在表中查找或生成一些记录都具有相同的内容,并生成散列键,然后排序键应该是您希望排序的内容,在我的例子中,这是优先级

该索引看起来像这样,以给出一个想法

我的无服务器文件在定义时如下所示

userStatusTable: #This table is used to track a users current status.
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:custom.userStatusTable}
        AttributeDefinitions: #UserID in this case will be created once and constantly updated as it changes with status regarding the user.
          - AttributeName: userId
            AttributeType: S
          - AttributeName: priority
            AttributeType: N
          - AttributeName: type
            AttributeType: S
        KeySchema:
          - AttributeName: userId
            KeyType: HASH
        ProvisionedThroughput:
            ReadCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.pstage}}
            WriteCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.pstage}}
        GlobalSecondaryIndexes:
          - IndexName: typePriorityIndex
            KeySchema:
              - AttributeName: type
                KeyType: HASH
              - AttributeName: priority
                KeyType: RANGE
            Projection:
              ProjectionType: ALL
            ProvisionedThroughput:
              ReadCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.pstage}}
              WriteCapacityUnits: ${self:custom.dynamoDbCapacityUnits.${self:custom.pstage}}

索引与排序无关。排序只是用于高效检索行的一种方法,因为排序数组中的搜索可以在对数时间O(logn)而不是线性时间O(n)内完成。这只是按排序顺序返回行的结果。但是,让我们关注一下查找要返回的确切行的能力(I/O,例如磁盘读取)

对于dynamodbfo进程来说,这种类型的查询(按组、状态和更多列)的过滤需求非常困难。效率是指DynamoDB需要从磁盘检索多少行,以确定哪些行要返回到客户端。如果它返回从表中读取的总行数的10%,则效率低下。这就是为什么常规的
扫描
过滤器
不如
索引查询
。过滤器是个谎言,因为它们仍然从数据库中读取项目,并计入已配置的容量。索引查询将从接近其实际返回的数字的存储行中检索。这是通过DynamoDB实现的,但仅限于单个分区(具有相同分区/散列键的项)和一个范围(从,>=,链接到my,该链接使用设计的主表)

这种方法需要修改UserStatus中的
group
modeling,从设置了字符串的单个记录修改为设置了字符串的多个记录。这是因为DynamoDB不支持(尽管这是一个很好的特性请求)对集合进行键控

主表用于更新/插入/删除,如下所示:

+--------+---------+-------+----------+----------+--------+
| userId | group   | type  | priority | loggedIn | status |
+--------+---------+-------+----------+----------+--------+
| 123    | default | admin | 1        | true     | idle   |
+--------+---------+-------+----------+----------+--------+
| 123    | orange  | admin | 1        | true     | idle   |
+--------+---------+-------+----------+----------+--------+
| 124    | default | admin | 3        | false    | idle   |
+--------+---------+-------+----------+----------+--------+
| 125    | orange  | admin | 2        | false    | idle   |
+--------+---------+-------+----------+----------+--------+
  • 分区/哈希键:userId
  • 排序键:组
在(组,优先级)上设置GSI。这将用于查询。是的,为此索引选择的组合将具有重复项:DynamoDB不需要考虑这一点,并且工作得很好

+---------+----------+--------+-------+----------+--------+
| group   | priority | userId | type  | loggedIn | status |
+---------+----------+--------+-------+----------+--------+
| default | 1        | 123    | admin | true     | idle   |
+---------+----------+--------+-------+----------+--------+
| default | 3        | 124    | admin | false    | idle   |
+---------+----------+--------+-------+----------+--------+
| orange  | 1        | 123    | admin | true     | idle   |
+---------+----------+--------+-------+----------+--------+
| orange  | 2        | 125    | admin | false    | idle   |
+---------+----------+--------+-------+----------+--------+
任务:

  • 更新此表上的用户需要更新/插入与该用户所属的组数量相同的行
  • 删除用户意味着删除该用户的所有项目
  • 查询由
    group=:group and priority>=:priority
    完成,在
    status='idle'和loggedIn=true上进行过滤
    
    • 一种变体是根据状态或loggedIn进行排序,因为您使用它们进行过滤,这有助于使查询更具选择性,然后根据客户机上的优先级进行排序

我应该遵循这种方法吗?我认为这是一个很好的设计,当有许多组,单个组包含多达20%的总用户,并且用户属于两个或两个组时。

我正在考虑可能为优先级创建一个全局二级索引,哈希为userId,这样至少可以按优先级排序。这能起作用吗?扫描不使用索引,你同意吗?否则,组上的全局索引,但它必须是字符串而不是集合,这将需要用户所在组的一条记录。我有一个想法,类型或多或少都是相同的,所以我可以使用类型作为哈希键,排序键将是优先级。哈希键的单个值是与扫描相同。@JosephAstrahan我看到您的表中没有范围键。因此您可以将
优先级
设置为范围键,然后上面的
扫描
将自动返回按
优先级
排序的结果。对于我的解决方案,我不确定的是双重排序?如果我想按“this”和“that”排序,那么我现在不知道如何做。也许我会创建更多的索引?我的类型对于用户可能不同,对于不同的用户类型。对于该类型的用户,我希望按优先级排序。理想情况下,按组筛选会更好,然后再排序。这将需要再次更改数据库,必要时我会这样做。如何做您建议在这种情况下设置数据库?而且我仍然不明白为什么我的类型和优先级全局索引在这种情况下不好?我将用另一种组设计更新我的答案。我真的很喜欢这种方法!非常感谢您花时间写这篇文章。这比我的方法更有意义。我将尝试实现到明天st thing会让你知道我的延迟是如何发生的,一旦我正确地测试了它,Goestory会让你知道的