dynamodb table table 为多用户共享应用程序设计的

dynamodb table tables design for multi user sharing applications

抱歉问题的抽象标题,但我会尝试在我的问题中详细解释我的意图。

我想创建一个提醒应用程序,其中每个用户在系统中都有单独的登录名,但 he/she 可以选择与另一个用户共享项目(在本例中为提醒),如果 he/she 选择。因此,当与该项目共享的用户在他的应用程序中搜索时,他也可以看到与他共享的提醒。

因此用户可以只为自己设置提醒 + 与他共享的提醒。

这是我的数据 access/retrieval 模式:

  1. 因此,当用户进入应用程序时,他应该能够看到他创建的提醒列表以及与他共享的提醒列表
  2. 从该列表中,他应该能够通过标签搜索提醒(我计划在 dynamodb 之外进行搜索,因为标签将是一个集合而不是标量字段,因此我无法在其上建立索引)并且应该能够按标题搜索提醒 3.A 用户应该能够更新或删除提醒 4.A 用户应该可以创建提醒 5.Also 用户应该只能看到未来的提醒,而不能看到过期的提醒

我的 table 和索引创建是使用以下 create_table 脚本创建的:

import boto3


def create_reminders_table():
    """Just create the reminders table."""
    session = boto3.session.Session(profile_name='dynamo_local')
    dynamodb = session.resource('dynamodb', endpoint_url="http://localhost:8000")
    table = dynamodb.create_table(
        TableName='Reminders',
        KeySchema=[
            {
                'AttributeName': 'reminder_id',
                'KeyType': 'HASH'
            }
        ],
        AttributeDefinitions=[
            {
                'AttributeName': 'reminder_id',
                'AttributeType': 'S'
            },
            {
                'AttributeName': 'user_id',
                'AttributeType': 'S'
            },
            {
                'AttributeName': 'reminder_title_reminder_id',
                'AttributeType': 'S'
            }
        ],
        GlobalSecondaryIndexes=[
            {
                'IndexName': 'UserTitleReminderIdGsi',
                'KeySchema': [
                    {
                        'AttributeName': 'user_id',
                        'KeyType': 'HASH'
                    },
                    {
                        'AttributeName': 'reminder_title_reminder_id',
                        'KeyType': 'RANGE'
                    }
                ],
                'Projection': {
                    'ProjectionType': 'INCLUDE',
                    'NonKeyAttributes': [
                        'reminder_expiration_date_time'
                    ]
                }
            }
        ],
        BillingMode='PAY_PER_REQUEST'
    )
    return table


if __name__ == '__main__':
    movie_table = create_reminders_table()
    print("Table status:", movie_table.table_status)

因此我们决定使用全局二级索引来允许用户搜索带有提醒标题的提醒。

现在要实现上述情况,其中用户还想与其他人分享他的提醒,我想对我的 table 架构进行以下更改。基本上我想将 user_id 属性重命名为 users_id 之类的东西,它最初包含创建它的用户的用户 ID,但如果该提醒与某人共享,那么第二个的 user_id user 也与创建者用户 id 连接并且 users_id 列被修改。

如果我这样做,我会想到 2 个问题:

  1. 我如何知道共享提醒的用户 user_id?可能现在我需要维护一个新的 table 来保存用户信息?或者我可以为此使用亚马逊 Cognito 等其他服务吗?

  2. 如果我在 users_id 列上仍然有全局二级索引,当我需要为用户搜索提醒时,查询需要像这样:select * from reminders where users_id startswith("Bob")( for例如).

  3. 我能想到的另一个选择(首选方式)是放弃创建 users_id 属性的想法,而不是保持 user_id 列原样。我会将 user_id 作为排序键 (RANGE) 键添加到 table,以便 reminder_iduser_id 的组合是唯一的。然后,当用户想要与其他用户共享他创建的提醒时,会在数据库中创建一个具有相同 reminder_id 和新用户 ID(即共享提醒的用户的用户 ID)的新条目)

任何对我困境的帮助都将不胜感激。

提前致谢。

您没有详细提及您的查询访问模式,使用 DynamoDB,您的数据模型源自查询访问模式。所以下面仅基于我对您可能需要的查询模式的想象。我可以离开了。

PK可以是user_id。 SK可以是用户保留的所有提醒的reminder_id。这使您可以执行 Query 以获得给定用户的所有提醒。主键是用户 ID 和提醒 ID 的组合,因此如果您要传递参考,请使用它(不仅仅是 reminder_id)。

通过将另一个项目放在共享对象的 user_id 下方来添加共享。这样,该用户的查询就可以检索他们自己的提醒以及与他们共享的提醒。

如果您需要人们列出他们分享了哪些提醒以及与他人分享了哪些提醒,您可以将其作为分享对象的列表放入提醒本身(如果列表足够短),或者创建一个如果列表可能很大,则该共享引用上的 GSI(针对 shared_by 属性)。

如果您需要查询用户的提醒并区分他们自己的提醒与共享的提醒,您可以在 SK 前面添加 SHARED#reminder_idSELF#reminder_id 以便在 SK 上添加 begins_with可以区分。

您可以通过多种方式改进它,但我认为它会针对“显示我的提醒和与我共享的提醒”用例进行优化,同时使共享(或撤消共享)易于实现。