【问题标题】:appengine many to many field update value and lookup efficientlyappengine 多对多字段更新值和高效查找
【发布时间】:2012-09-27 00:10:17
【问题描述】:

我正在使用带有 python 2.7 和 webapp2 框架的 appengine。我使用 ndb.model。

我有以下型号:

class Story(db.Model);
    name = db.StringProperty()

class UserProfile(db.Model):
    name = db.StringProperty()
    user = db.UserProperty()

class Tracking(db.Model):
   user_profile = db.ReferenceProperty(UserProfile)
   story = db.ReferenceProperty(Story)
   upvoted = db.BooleanProperty()
   flagged = db.BoolenProperty()

用户可以对故事进行投票和/或标记,但只能进行一次。因此,我提出了上述模型。 现在,当用户点击upvote 链接时,我会在数据库上尝试查看用户是否还没有投票,因此我会尝试执行以下操作:

  1. 获取ID为up = db.get(db.Key.from_path('UserProfile', uid))的用户实例

  2. 然后获取故事实例如下s_ins = db.get(db.Key.from_path('Story', uid))

  3. 现在轮到检查是否存在基于这两个的Tracking,如果则不允许投票,否则允许他投票并更新跟踪 实例。

在给定 ID(db.key().id()) 为 user_profilestory 的情况下,获取 Tracking 实例最方便的方法是什么?

保存Tracking 模型(已给出用户个人资料 ID 和故事 ID)最方便的方法是什么?

有没有更好的方法来实现跟踪?

【问题讨论】:

    标签: python database google-app-engine app-engine-ndb


    【解决方案1】:

    您可以尝试使用键列表进行跟踪,而不是使用单独的跟踪/用户/故事条目:

    class Story(db.Model);
      name = db.StringProperty()
    
    class UserProfile(db.Model):
      name = db.StringProperty()
      user = db.UserProperty()
    
    class Tracking(db.Model):
      story = db.ReferenceProperty(Story)
      upvoted = db.ListProperty(db.Key)
      flagged = db.ListProperty(db.Key)
    

    因此,当您想查看用户是否为给定故事投票时:

    Tracking.all().filter('story =', db.Key.from_path('Story', uid)).filter('upvoted =', db.Key.from_path('UserProfile', uid)).get(keys_only=True)
    

    现在唯一的问题是投票/标记列表的大小不能变得太大(我认为限制是 5000),所以你必须创建一个类来管理它(也就是说,当添加到赞成/标记的列表,检测是否存在 X 条目,如果存在,则启动一个新的跟踪对象以保存附加值)。您还必须进行事务处理,并且对于 HR,您有每秒 1 次写入的阈值。这可能是也可能不是问题,具体取决于您的预期用例。绕过写入阈值的一种方法是使用拉取队列实现支持/标记,并有一个 cron 作业根据需要拉取和批量更新跟踪对象。

    这种方法有其优点/缺点。最明显的缺点是我刚刚列出的那些。然而,优点可能是值得的。您可以从单个列表(或多个,具体取决于故事的受欢迎程度)中获取对故事进行投票/标记的用户的完整列表。您可以获得完整的用户列表,而对数据存储的查询要少得多。此方法还应占用更少的存储、索引和元数据空间。此外,将用户添加到跟踪对象会更便宜,而不是为每个属性写入一个新对象 + 2 次写入,您只需为对象支付 1 次写入 + 为列表条目写入 2 次(9 次写入 vs 3 次写入)用于将用户添加到预先存在的跟踪故事,或 9 vs 7 用于未跟踪的故事)

    【讨论】:

      【解决方案2】:

      你的提议听起来很合理。

      请勿使用应用引擎生成的密钥进行跟踪。因为故事/用户的组合应该是唯一的,所以创建您自己的密钥作为故事/用户的组合。类似的东西

      tracking = Tracking.get_or_insert(str(story.id) + "-" + str(user.id), **params)
      

      如果您知道故事/用户,那么您始终可以通过键名获取跟踪。

      【讨论】:

      • 能否详细说明 (str(story.id) + "-" + str(user.id), **params)
      • 您可以使用任意字符串,因此只需通过将用户标识附加在一起来创建一个,即“1234-890123”。检查参数的 get_or_insert() 文档(您还需要验证是否创建了新实体,或者获取是否成功)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 2017-12-27
      • 2015-12-13
      • 1970-01-01
      • 2020-08-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多