管理 AWS DynamoDB 中分层文件夹结构中可用的文档

Gag*_*jaj 2 database-design nosql amazon-dynamodb dynamodb-queries

我是 DynamoDB(文档数据库)的新手,需要帮助设计 nosql 数据库中的表结构。

我需要管理不同文件夹中可用的文档。文件夹层次结构可以转到第 n 级,并且同一文档可以在多个文件夹中使用。

在关系数据库的情况下,我可以维护不同表中的层次结构和文档,并通过在这些表上应用连接来提取所需的信息。

我需要知道在 DynamoDB 表中存储这些数据的最佳方式,以便可以最有效的方式提取信息。每个用户都有一定的权限,他/她可以根据这些权限查看或编辑文档。

目前我正在尝试将其存储在以下结构中:

documents = [
{
    _id: ...,
    title: "...",
    date_uploaded: ...,
    folders: [
        folderId,
        ...
    ]
},
...
]

folders = [
{
    _id: ...,
    title: "..."
}
]
Run Code Online (Sandbox Code Playgroud)

在 documentId 的帮助下,我可以从文件夹表中提取文档所在的文件夹列表以及该文件夹的详细信息,但不确定如何维护文件夹层次结构。

有人可以帮我解决这个问题吗?

tle*_*eef 5

你在这里有一个多对多的关系。一个文件夹可以有多个文档,一个文档可以在多个文件夹中。没有一种方法可以对这些类型的关系进行建模,因为它们往往是特定于应用程序的,并且高度依赖于您的访问模式。既然如此,我将需要对您的应用程序做出一些假设才能回答您的问题。我会尽量说明我假设的地点和内容。

通常,使用 NoSQL,您可以设计架构并组织数据以支持应用程序中的特定视图。很多时候涉及非规范化数据,特别是在多对多关系的情况下,这就是为什么这些类型的关系的策略往往如此特定于应用程序。

在下面的示例中,我将假设您有某种主从视图,其中主列表包含子文件夹和特定文件夹中文档的摘要信息,详细视图显示有关当前所选文档的所有信息.

模式


首先,我将根据您上面的架构定义架构,但稍作修改以更适合 DynamoDB。

文件夹

{
  "id": String,
  "parent_id": String,
  "name": String,
}
Run Code Online (Sandbox Code Playgroud)

文档

{
  "id": String,
  "title": String,
  "contents": String,
  "date_modified": String,
  "date_uploaded": String,
}
Run Code Online (Sandbox Code Playgroud)

文档模型是不言自明的。此外,我们将创建一个 DocumentSummary,其中仅包含有关文档的摘要信息。

文件摘要

{
  "id": String,
  "parent_id": String,
  "title": String,
  "date_uploaded": String,
}
Run Code Online (Sandbox Code Playgroud)

根据经验,DocumentSummary 模型应该是 Document 模型的一个子集,并且只包含不可变的字段,例如date_uploaded,或者变化非常缓慢的字段,例如title。诸如此类的字段date_modified可能会非常迅速地变异,这可能会导致问题(我们稍后会看到原因)。此外,诸如此类的字段contents不应进入我们的汇总模型。除了contents是一个快速静音的领域之外,它没有任何“摘要”。请记住,我们的汇总模型与完整模型越接近,我们的汇总模型的用处就越小。在某些时候,我们不妨扔掉我们的汇总模型,只使用我们的完整模型。


我们将有两个表,DocumentTable 和 DirectoryTable。

文件表

Hash Key: "id"
Run Code Online (Sandbox Code Playgroud)

DocumentTable 包含我们的文档,并为我们提供了执行 CRUD 操作的能力 id

目录表

Hash Key: "parent_id"
Sort Key: "id"
Run Code Online (Sandbox Code Playgroud)

DirectoryTable 将包含 Folders 和 DocumentSummaries。由于此表包含两种不同的类型,因此每种类型的 ID 不能冲突非常重要。我建议在您的 ID 前面加上命名空间,例如“folder-123”和“document-123”。

DirectoryTable 使我们能够查询给定文件夹中的所有子文件夹和文档摘要,并允许我们通过parent_id和更新文件夹和文档摘要id

例如,如果我们要查找“folder-123”内的所有子文件夹和文档摘要,我们可以使用以下参数进行查询。

{
    "TableName": "DirectoryTable",
    "KeyConditionExpression": "parent_id = :parent_id",
    "ExpressionAttributeValues": {
        ":parent_id": {"S": "folder-123"},
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:对于顶级文件夹和文档,您将需要使用一个虚拟的,parent_id例如“root”

此外,我们可能想要查询特定文档所在的文件夹。要回答这个问题,我们需要在 DirectoryTable 上创建一个全局二级索引 (GSI)

id-parent_id-index(目录表 GSI)

Hash Key: "id"
Sort Key: "parent_id"
Run Code Online (Sandbox Code Playgroud)

现在,我们可以使用带有以下参数的 Query 来查找 ID 为“document-123”的文档的所有父文件夹 ID。

{
    "TableName": "DirectoryTable",
    "IndexName": "id-parent_id-index",
    "KeyConditionExpression": "id = :id",
    "ExpressionAttributeValues": {
        ":id": {"S": "document-123"}
    }
}
Run Code Online (Sandbox Code Playgroud)

您可能想知道如何通过id. 您可以简单地id-parent_id-index再次使用与上述相同的查询参数,将“document-123”替换为文件夹 ID,例如“folder-123”。如果你做对了,这应该会产生一个长度为 1 的 Items 数组。

最后,我们需要一种方法来更新 DocumentSummaries,当其中一个重复字段在相应的 Document 上更新时。为此,我们可以使用 DynamoDB Streams。在 DocumentTable 上创建一个 DynamoDB Stream 并监听更新事件。如果更新事件指示重复字段之一已被修改,请使用id-parent_id-index查找文档的所有父文件夹,然后通过parent_id和更新 DocumentSummary id。此更新可能非常昂贵,因为它是扇出问题的一个示例,例如,单个 Document 更新导致 N 个 DocumentSummary 更新。最小化这个成本很重要,特别是在大规模时,这就是为什么我们只想在我们的 DocumentSummary 中包含不可变或缓慢变异的字段。