遵循AppEngine上的数据存储模型结构 - 按日期订购关注者

时间:2011-02-10 15:43:24

标签: python google-app-engine social-networking

在我的应用中,用户可以关注其他用户,并在他们关注的人执行活动时获得更新。

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

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)

所以,我想通过关注日期(我在上面的模型中没有跟踪)来命令my_user关注者,但我不确定最好的方法是什么。以下是我能想到的选项:

1)使用“桥”模型代替联系人(db.Model)的当前结构:

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

但是,我仍然需要弄清楚如何确保我有独特的关注者 - >以下实体:follower = user1,follow = user2不应该重复。如果我将2个过滤器应用于我的查询,我可以这样做。

2)保持当前的模型结构,但不是在Contacts(db.Model)中有一个键列表,而是存储一个元组:[user_key,date_created],如下所示:

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()中的每个字符串中提取用户键和date_created - 然后我可以按创建日期订购用户密钥列表

3)最后的解决方案(显然效率不高):保留原始数据库结构,并将用户跟踪活动存储在单独的模型中 - 每个跟随操作都与date_created字段分开存储。仅使用此表可以按日期排序用户关注者列表。这当然意味着我会做两个数据存储区 - 一个到Contacts(),另一个到FollowNewsFeed(),如下所示:

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

有关处理此问题的最佳方法的任何见解都非常感谢:)

谢谢!

1 个答案:

答案 0 :(得分:3)

我会使用模型从用户映射到目标,而不是列表:

  1. 插入新实例或删除现有实例可能比修改庞大的列表并重新保存它更快。此外,随着后续规模的增长,您可以查询列表的一个子集,而不是将其全部取出(请参阅下面的原因)。

  2. 您可以获得额外的属性空间,而不必担心需要重新设计和随意使用列表。

  3. 不必担心列表(each item takes up a slot, up to 5000)的索引限制。

  4. 很遗憾,您可能会点击another limit much sooner

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

    这意味着每个元素都会消耗一个插槽[ex。 in (1,2,3) = 3个插槽]。因此,即使数量相对较少(约30个粉丝),您也需要多次访问数据库并附加结果。

    假设人们不想在他们的页面上疯狂地花费数百年的时间来加载和计时,那么他们需要对他们可以关注的人数进行某种限制。在追踪100人的情况下,您需要进行4-5次旅行,并且必须通过javascript对应用程序或客户端的数据进行排序。