appengine许多到许多字段更新值和有效查找

时间:2012-09-27 00:10:17

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

我在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. 获取身份为up = db.get(db.Key.from_path('UserProfile', uid))

  2. 的用户实例
  3. 然后按如下方式获取故事实例s_ins = db.get(db.Key.from_path('Story', uid))

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

  5. Trackingdb.key().id()的ID(user_profile获取 story实例时,最方便的方法是什么?

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

    是否有更好的方法来实施跟踪?

2 个答案:

答案 0 :(得分: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)

现在唯一的问题是upvoted / flagged列表的大小不能太大(我认为限制是5000),所以你必须创建一个类来管理它(也就是说,添加时)对于upvoted / flagged列表,检测是否存在X条目,如果存在,则启动一个新的跟踪对象以保存其他值)。您还必须进行此事务处理,并且使用HR时,您的每秒写入阈值为1。根据您的预期用例,这可能是也可能不是问题。围绕写入阈值的方法是使用pull-queues实现upvotes / flags,并根据需要提供一个cron作业来拉取和批量更新跟踪对象。

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

答案 1 :(得分:0)

你的建议听起来很合理。

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

这样的东西
tracking = Tracking.get_or_insert(str(story.id) + "-" + str(user.id), **params)

如果你知道故事/用户,那么你总是可以按密钥名称来获取跟踪。