一个好的数据模型用于查找用户的喜欢故事

4 投票
4 回答
880 浏览
提问于 2025-04-15 15:03

最初的设计

我最开始是这样设置我的 Models 的:

class UserData(db.Model):
    user = db.UserProperty()
    favorites = db.ListProperty(db.Key) # list of story keys
    # ...

class Story(db.Model):
    title = db.StringProperty()
    # ...

在每个显示故事的页面上,我会查询当前用户的用户数据:

user_data = UserData.all().filter('user =' users.get_current_user()).get()
story_is_favorited = (story in user_data.favorites)

新的设计

在看了这个讲座之后: Google I/O 2009 - 可扩展的复杂应用程序在 App Engine 上,我想知道是否可以更高效地设置这些东西。

class FavoriteIndex(db.Model):
    favorited_by = db.StringListProperty()

Story Model 还是一样,但我去掉了 UserData Model。新的 FavoriteIndex Model 的每个实例都有一个 Story 实例作为父级。而每个 FavoriteIndex 都在它的 favorited_by 属性中存储了一份用户 ID 的列表。

如果我想找到某个用户收藏的所有故事:

index_keys = FavoriteIndex.all(keys_only=True).filter('favorited_by =', users.get_current_user().user_id())
story_keys = [k.parent() for k in index_keys]
stories = db.get(story_keys)

这种方法避免了与 ListProperty 相关的序列化和反序列化问题。

效率与简单性

我不确定新的设计有多高效,特别是在用户决定收藏 300 个故事之后,但我喜欢它的原因有:

  1. 被收藏的故事是和用户关联的,而不是和她的 user data 关联。

  2. 在我显示 story 的页面上,询问这个 story 是否被收藏是相当简单的(不需要调取一个单独的包含用户数据的实体)。

    fav_index = FavoriteIndex.all().ancestor(story).get()
    fav_of_current_user = users.get_current_user().user_id() in fav_index.favorited_by
    
  3. 获取所有收藏了某个故事的用户列表也很简单(使用第 2 点的方法)。

有没有更简单的方法?

请帮帮我。这种事情通常是怎么做的?

4 个回答

1

你可以把收藏索引想象成在两个模型之间的连接

class FavoriteIndex(db.Model):
    user = db.UserProperty()
    story = db.ReferenceProperty()

或者

class FavoriteIndex(db.Model):
    user = db.UserProperty()
    story = db.StringListProperty()

这样的话,当你根据用户查询时,会返回每个用户收藏的故事对应的一个 FavoriteIndex 对象

你也可以根据故事来查询,看看有多少用户收藏了它。

你不想随便去查找任何东西,除非你知道它的数量很少。

1

我不打算直接回答你的问题,但我可以给你一个很小的建议:你可以把这段代码:

if story in user_data.favorites:
    story_is_favorited = True
else:
    story_is_favorited = False

换成这一行:

story_is_favorited = (story in user_data.favorites)

如果你不想的话,其实也可以不把story in user_data.favorites放在括号里;我只是觉得这样看起来更清晰。

2

你所描述的方案很好。不过,你还可以进一步优化:对于每个收藏的故事,创建一个叫做'UserFavorite'的实体,把它作为相关故事条目的子实体(或者说,作为UserInfo条目的子实体),并把这个实体的名字设置为用户的唯一ID。这样一来,你就可以通过简单的获取操作来判断用户是否收藏了某个故事:

UserFavorite.get_by_name(user_id, parent=a_story)

获取操作的速度比查询快3到5倍,所以这是一个很大的提升。

撰写回答