Table 在 DynamoDB 中设计

Table design in DynamoDB

我是 NoSQL DB 和 Serverless 的初学者。我的应用有一个名为 Trips 的 table。 table的参数是{id, route, cost, selling, type, date, LR, asset }和一堆其他不相关的文档号,其中id由uuid生成。

现在我想查询数据库给我

  1. Return 使用日期参数的日期范围内的所有行程。
  2. Return 使用日期和资产参数在给定时间段内资产的所有行程。
  3. Return 使用日期路线参数在给定时间段内路线的所有行程。

2 和 3 使用 keyConditionExpression 工作正常,但对于 1,我需要在扫描中使用 filterExpression 而不是查询,这可能会使它相对较慢,因为它是在查询完成后执行的。有没有更好的方法来形成模式?

Trips table 中,架构是这样的

 tripTable:
  Type: "AWS::DynamoDB::Table"
  Properties:
    AttributeDefinitions:
      [
        { "AttributeName": "id", "AttributeType": "S" },
        { "AttributeName": "date", "AttributeType": "S" },
        { "AttributeName": "Asset", "AttributeType": "S" },
        { "AttributeName": "Route", "AttributeType": "S" },
      ]

    KeySchema:
      [
        { "AttributeName": "date", "KeyType": "HASH" },
        { "AttributeName": "id", "KeyType": "RANGE" },
      ]
    ProvisionedThroughput:
      ReadCapacityUnits: 5
      WriteCapacityUnits: 5
    StreamSpecification:
      StreamViewType: "NEW_AND_OLD_IMAGES"
    TableName: ${self:provider.environment.TRIPS}
    GlobalSecondaryIndexes:
      - IndexName: TripsVSAssets
        KeySchema:
          - AttributeName: asset
            KeyType: HASH
          - AttributeName: date
            KeyType: RANGE
        Projection:
          ProjectionType: ALL
        ProvisionedThroughput:
          ReadCapacityUnits: "5"
          WriteCapacityUnits: "5"
        GlobalSecondaryIndexes:
      - IndexName: RoutesVSAssets
        KeySchema:
          - AttributeName: route
            KeyType: HASH
          - AttributeName: date
            KeyType: RANGE
        Projection:
          ProjectionType: ALL
        ProvisionedThroughput:
          ReadCapacityUnits: "5"
          WriteCapacityUnits: "5"

您还需要一个索引列,其中分区键(哈希类型)将是一个随机数,比方说从 0 到 20。排序键(范围类型),再次将日期放在那里。

所以要查询某个时间段内的所有行程,需要并行查询20次,partition Key为0到20之间的每个数字,Sort Key为时间范围。

https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-modeling-nosql-B.html

检查上面的指南,转到页面末尾的 table 并检查第 5 个条目

如果您在此处进行扫描,那么 dynamoDB 将针对每个分区键向您收费。在上面提到的并行查询技术中,您只需为 N 个查询付费(在上述情况下为 20 个)。

我最近遇到了类似的问题,并选择使用 year 作为分区键和日期作为排序键。这对我的数据量来说是正确的,让我可以按日期查询,而且大多数情况下只是 运行 单个查询。如果您有大量数据,也许 month 甚至 week 会更合适(或完全不同)。

然后,使用我的方法,我只需要检查我想要查看的日期范围是否跨越两年,在这些情况下(即很少),Lambda 会进行两次查询并合并结果。我在下面包含了一些代码草案,以防它有用(可能有更好的方法,但这对我有用!)我还推荐快速阅读:https://aws.amazon.com/blogs/database/choosing-the-right-dynamodb-partition-key/.

module.exports.getLatest = async event => {

  // some date and formatting code here not included

  var params1 = {
    ExpressionAttributeNames: { "#date": "date", "#year": "year" },
    ExpressionAttributeValues: {
      ':d': isoDate,
      ':y1': y1
     },
   KeyConditionExpression: '#year = :y1 AND #date > :d',
   TableName: process.env.HEADLINES_TABLE
  }

  if (y1 != y2) {
   // define var params2 (the same as params1 except it uses y2)
  }

  try {
    let result;

    // if the date range cuts across partitions (years), fire off two queries and wait for both

    if(y1 != y2) {
        let resultPromise1 = client.query(params1).promise();
        let resultPromise2 = client.query(params2).promise();
        const [result1, result2] = await Promise.all([resultPromise1,resultPromise2]);
        result = [...result1.Items, ...result2.Items];
    } else { 
        result = await client.query(params1).promise();
    }

    return {
      // stringify and return result.Items, statuscode 200 etc.
    }
  }
  // catch {} code here (irrelevant for the answer)
}