Nosql dynamodb的数据建模,其中实体具有一对多和多对多关系

Nosql dynamodb的数据建模,其中实体具有一对多和多对多关系,nosql,amazon-dynamodb,Nosql,Amazon Dynamodb,我是NoSql世界的新手。我正在用dynamodb构建一个无服务器应用程序。在关系数据库中,当我有3个实体,如post、post_likes和post_标记时,我会有几个表,并使用连接来获取数据。但是,我想知道如何为一个场景创建一个NoSql结构,在这个场景中,post与Like有一对多的关系,而与标记有多对多的关系 Post型号: user_id <string> attachment_url <string> description <string> pu

我是NoSql世界的新手。我正在用dynamodb构建一个无服务器应用程序。在关系数据库中,当我有3个实体,如post、post_likes和post_标记时,我会有几个表,并使用连接来获取数据。但是,我想知道如何为一个场景创建一个NoSql结构,在这个场景中,post与Like有一对多的关系,而与标记有多对多的关系

Post型号:

user_id <string>
attachment_url <string>
description <string>
public <boolean>
user_id <string>
post_id <string>
type <string>
name <string>
那么这张桌子看起来像这样:

Partition key | Sort key | data attributes 
tag_name      | post_id  | public | user_id | likes[] | other post attributes...

我已经设置了2个全局二级索引。 第一个全球二级指数:

分区键设置为public,排序键设置为post_id

第二个全球二级指数:

分区键设置为user\u id,排序键设置为post\u id

这样一来,对于一篇文章的每个标签,我都会在表中有一个该文章的副本。我认为通过使用标记作为第一个过滤器,如果需要通过标记查询帖子,我可以高效地查询帖子

但是,如果我只通过公共状态或用户id进行查询,我将获得每个标签的所有帖子副本

或者我应该在表中有3个独立的实体,标签帖子喜欢,如果我通过标签获取帖子,我会首先通过一个标签查询所有的帖子id,然后进行第二个查询以获取帖子和它们的喜欢id,然后执行第三个查询以获取likes数组。 我不知道这方面的最佳实践是什么,因为我才刚刚开始使用dynamodb


那么这个数据库结构应该是什么样子呢?

通过深入思考访问模式和定义实体(帖子、用户、喜好等),您已经有了一个很好的开始。如您所知,全面了解访问模式对于将数据存储在DynamoDB中至关重要

在回顾我的答案时,请记住这只是一个解决方案。DynamoDB在定义数据模型时给了您大量的灵活性,这可能是好事,也可能是坏事!这个答案并不意味着是对这些访问模式进行建模的方法。相反,这是实现这些访问模式的一种方法。让我们开始吧

我想首先列出我们需要建模的实体,以及每个实体的主键。在这篇文章中,我将使用复合主键,它们是由分区键(PK)和排序键(SK)组成的键。让我们从一张空白表格开始,边走边填

         Partition Key             Sort Key
User
Post
Tag

使用者 用户是应用程序的核心,因此我将从这里开始

让我们从定义一个用户模型开始,该模型允许我们通过ID标识用户。我将使用模式
User#
来表示用户实体的PK和SK

这支持以下访问模式(为了简单起见,以伪代码为例):

  • 按ID获取用户
  • 我将使用新的PK/SK模式为用户更新表

             Partition Key             Sort Key
    User     USER#<user_id>           USER#<user_id>
    Post
    Tag
    
    现在我们已经对用户、帖子和标签进行了建模。但是,我们只讨论了四种访问模式中的一种。让我们看看如何使用辅助索引来支持您的访问模式

    注意:您也可以用完全相同的方式建模
    喜欢的对象

    定义二级索引 辅助索引允许您在数据中支持其他访问模式。让我们定义一个非常简单的二级索引,看看它如何支持各种访问模式

    我将创建一个二级索引,用于交换基表中的PK/SK模式。此模式称为,如下所示:

    Partition key | Sort key | data attributes 
    tag_name      | post_id  | public | user_id | likes[] | other post attributes...
    

    我们在这里所做的只是交换了基表的PK/SK模式,这使我们能够访问另外两种访问模式:

  • 凭身份证取信
  • 获取所有私人邮件
  • 获取所有公共职位
  • 记住,post ID是KSUID,因此它们自然会在您的结果中按发布日期排序

    热分区一词 将所有帖子存储在单个分区中可能会导致应用程序扩展时出现错误。解决这一问题的一种方法是跨多个分区分发帖子。如何做到这一点完全取决于您自己,也取决于您的应用程序

    避免单个
    POST
    分区的一种策略可能涉及按创建日/周/月/等对帖子进行分组。例如,您可以使用
    POST
    作为您在
    PostByStatus
    二级索引中的主键,而不是使用
    Posts#-
    ,如下所示:

    Partition key | Sort key | data attributes 
    tag_name      | post_id  | public | user_id | likes[] | other post attributes...
    

    您的应用程序在获取帖子时需要考虑这种模式(例如,从当前月份开始,然后向后走,直到获取足够的结果),但是您需要将负载分散到多个分区

    收尾
    我希望本练习能为您提供一些有关如何对数据建模以支持特定访问模式的想法。DynamoDB中的数据建模需要时间才能正确,并且可能需要多次迭代才能为您的特定应用程序工作。这可能是一个陡峭的学习曲线,但回报是一个能够为应用程序带来规模和速度的解决方案。

    到目前为止,您尝试过哪些主键?我可能弄错了,但您关于索引的问题意味着您正试图在DynamoDb中创建类似SQL的索引。DynamoDB确实有“二级索引”的概念,但它与SQL数据库中的索引没有关系。我还没有做任何事情。在这个问题上,我可能不太清楚,我只是不确定应该设置什么作为散列和排序键,或者只是在这种情况下构建数据库。您的第四种访问模式是“获取一篇文章”。你是通过一个帖子ID,一个用户ID,或者两者兼而有之的方式获得一篇帖子吗
    ddbClient.query(PK = USER#<user_id>, SK begins_with "POST#")
    
             Partition Key             Sort Key
    User     USER#<user_id>           USER#<user_id>
    Post     USER#<user_id>           POST#<post_id>
    Tag
    
    
             Partition Key             Sort Key
    User     USER#<user_id>           USER#<user_id>
    Post     USER#<user_id>           POST#<post_id>
    Tag      POST#<post_id>           TAG#<tag_name>
    
    
    ddbClient.query(IndexName = InvertedIndex, PK = POST#<post_id>)
    
    ddbClient.query(IndexName = InvertedIndex, PK = TAG#<tag_name>)
    
    ddbClient.query(IndexName = PostByStatus, PK = POST)
    
    ddbClient.query(IndexName = PostByStatus, PK = POST, SK begins_with "PRIVATE#")
    
    ddbClient.query(IndexName = PostByStatus, PK = POST, SK begins_with "PUBLIC#")