在AppEngine上遵循数据存储模型结构 - 按日期排序关注者

5 投票
1 回答
590 浏览
提问于 2025-04-16 11:34

在我的应用程序中,用户可以关注其他用户,并在他们关注的人进行活动时收到更新。

我以这种方式存储关注关系:

class User(db.Model):
  ''' User details '''
  username = db.StringProperty()

class Contacts(db.Model):
    '''Store users contacts
       parent= User (follower)
       key_name= Users username (follower)
       contacts = A list of keys of Users that a User follows '''
    contacts = db.ListProperty(db.Key)
    last_updated = db.DateTimeProperty(auto_now=True)

获取关注者和用户关注的用户(关注者和被关注者):

'''Get Users that my_user follows'''
my_user = User().all().fetch(1)
contacts = Contacts.get_by_key_name(my_user.username).contacts

''' get my_user followers - copied from an answer here on stackoverflow '''
follower_index = models.Contacts.all(keys_only=True).filter('contacts =',my_user)
follower_keys = [f.parent() for f in follower_index]
followers = db.get(follower_keys)

现在,我想按关注日期对我的用户的关注者进行排序(但在上面的模型中我并没有跟踪这个日期),我不太确定最好的方法是什么。以下是我想到的几个选项:

1) 不使用当前的联系人结构(Contacts(db.Model)),而是使用一个“桥接”模型:

class Contacts(db.Model):
  follower = db.ReferenceProperty(User)
  following = db.ReferenceProperty(User)
  date_created = db.DateTimeProperty(auto_now_add=True)

不过,我仍然需要弄清楚如何确保关注者和被关注者的关系是唯一的:比如关注者=user1,关注的用户=user2,这种关系不能重复。我想如果我对查询应用两个过滤器,就可以做到这一点。

2) 保持当前的模型结构,但不在联系人(Contacts(db.Model))中使用一个键的列表,而是存储一个元组:[用户键, 创建日期],如下所示:

class Contacts(db.Model):
        '''Store users contacts
           parent= User (follower)
           key_name= Users username (follower)
           contacts = A list of Tuples: User.key(), date_created '''
        contacts = db.StringListProperty()
        last_updated = db.DateTimeProperty(auto_now=True)

不过,这样的话我就得处理联系人列表: - 我需要从StringList()中的每个字符串中提取用户键和创建日期 - 然后我可以按创建日期对用户键的列表进行排序

3) 最后一个解决方案(显然效率不高):保持原来的数据库结构,把用户关注活动存储在一个单独的模型中 - 每次关注操作单独存储,并带有一个创建日期字段。这个表只用来按日期对用户关注者的列表进行排序。当然,这意味着我需要进行两次数据存储操作 - 一次是对Contacts(),另一次是对FollowNewsFeed(),如下所示:

Class FollowNewsFeed(db.Model):
  ''' parent = a User follower'''
  following = db.ReferenceProperty(User)
  date_created = db.DateTimeProperty(auto_add_now=True)

对于处理这个问题的最佳方法,任何见解都非常感谢 :)

谢谢!

1 个回答

3

我建议用一个模型来把用户和他们想要的目标联系起来,而不是用一个列表:

  1. 插入一个新的实例或者删除一个已有的实例,通常会比修改一个很大的列表然后重新保存要快。而且,随着关注的人数增加,你可以只查询列表的一部分,而不是把整个列表都取出来(下面会解释原因)。

  2. 这样你可以有更多的属性空间,也不需要担心将来需要重新设计和调整列表的问题。

  3. 使用列表时不需要担心索引的限制 (每个项目占用一个位置,最多5000个)

不幸的是,你可能会很快遇到 另一个限制

A single query containing != or IN operators is limited to 30 sub-queries.

这意味着每个元素都会占用一个位置 [例如 in (1,2,3) = 3个位置]。所以即使关注的人数相对较少(大约30个关注者),你也需要多次访问数据库并合并结果。

假设人们不想让他们的页面加载得慢得像要几百年才能完成,你就需要对他们能关注多少人设置一个限制。如果关注人数达到100,你可能需要进行4到5次数据库访问,并且需要在你的应用程序内部或者通过JavaScript在客户端对数据进行排序。

撰写回答