【问题标题】:modelling the google datastore/python建模谷歌数据存储/python
【发布时间】:2010-10-22 10:14:08
【问题描述】:

您好,我正在尝试构建一个应用程序,其模型类似于以下模型:-(虽然将两个模型合并为一个并使用它们很容易,但这在实际应用程序中是不可行的)

class User(db.Model):
     username=db.StringProperty()
     email=db.StringProperty()

class UserLikes(db.Model):
      username=db.StringProperty()
      food=db.StringProperty()

目标-用户登录后输入他喜欢的食物,应用程序依次返回所有其他喜欢该食物的用户。 现在假设用户 Alice 输入她喜欢 "Pizzas" ,它被存储在数据存储中。她注销并再次登录。此时,我们在数据存储中查询她喜欢的食物,然后再次查询所有喜欢该食物的用户。如您所见,这是两个数据存储查询,这不是最好的方法。我相信肯定会有更好的方法来做到这一点。有人可以帮忙吗?

[更新:-或者可以这样做,我更改第二个模型,使用户名成为一个多值属性,所有喜欢该食物的用户都可以在其中存储..但是我在这里有点不清楚]

[编辑:-您好,感谢您的回复,但我发现下面的两种解决方案都有些矫枉过正。我试着像下面那样做。请你看看这个并提出建议。我维护了相同的两个表,但是将它们更改如下:-

class User(db.Model):
    username=db.StringProperty()
    email=db.StringProperty()

class UserLikes(db.Model):
     username=db.ListProperty(basestring)
     food=db.StringProperty()

现在,当 2 个用户更新他们喜欢的相同食物时,它会被存储起来

'比萨'---->'爱丽丝','鲍勃'

我的数据库查询在这里检索数据变得非常容易

query=db.Query(UserLikes).filter('username =','Alice').get()

然后我可以像

一样对其进行迭代
    for elem in query.username:
          print elem

现在如果有如下两种食物:-

'pizza' ----> 'Alice','Bob'
'bacon'----->'Alice','Fred'

我使用与上面相同的查询,并遍历查询,然后是用户名。

我对此很陌生,意识到这可能是错误的。请推荐!

【问题讨论】:

    标签: python google-app-engine google-cloud-datastore


    【解决方案1】:

    除了您拥有的关系模型之外,您还可以根据您的具体用例以其他两种方式处理此问题。您的更新有一个好主意,使用 ListProperty。查看 Brett Slatkin 在Relation Indexes 上的任务,了解一些背景信息。

    您可以在包含食物列表的用户上使用子实体(关系索引):

    class UserLikes(db.Model):
        food = db.StringListProperty()
    

    然后,当您创建 UserLikes 实例时,您会将与其相关的用户定义为父级:

    likes = UserLikes(parent=user)
    

    这使您可以查询其他非常喜欢特定食物的用户:

    like_apples_keys = UserLikes.all(keys_only=True).filter(food='apples')
    user_keys = [key.parent() for key in like_apples_keys]
    users_who_like_apples = db.get(user_keys)
    

    但是,可能更适合您的应用程序的方法是使关系成为食物的孩子:

    class WhoLikes(db.Model):
        users = db.StringListProperty()
    

    在创建like时将key_name设置为食物的名称:

    food_i_like = WhoLikes(key_name='apples')
    

    现在,获取所有喜欢苹果的用户:

    apple_lover_key_names = WhoLikes.get_by_key_name('apples')
    apple_lovers = UserModel.get_by_key_names(apple_lover_key_names.users)
    

    要让所有喜欢同一个用户的用户:

    same_likes = WhoLikes.all().filter('users', current_user_key_name)
    like_the_same_keys = set()
    for keys in same_likes:
       like_the_same_keys.union(keys.users)
    same_like_users = UserModel.get_by_key_names(like_the_same_keys)
    

    如果您有很多赞,或者很多用户有相同的赞,您需要对流程进行一些调整。您将无法获取 1,000 名用户。

    【讨论】:

    • 该链接上的精彩教程.. 谢谢.. 请在上面的帖子中查看我编辑的解决方案。我相信我应该做点傻事!
    • 你正在有效地按照我的建议去做。最大的区别之一是您使用属性来存储 food 的值,而不是使用 key_name。当您试图找到所有喜欢食物x 的用户时,使用 key_name 会更有效。但是,如果您的列表将包含数千名用户,那么包含一个属性可能是最简单的。确保您使用的是 Appstats (code.google.com/appengine/docs/python/tools/appstats.html),这样您就可以准确地看到幕后发生的事情。
    • 如果一种食物被超过 5000 名用户点赞怎么办?
    • 处理超过 5000 件的情况的一种常用方法是添加“分片”。基本上,添加另一个 RelationIndex 实体,其 key_name 类似于“apples;1”。您只需要添加更多逻辑来处理这些情况。它可能看起来像:如果列表中有 5,000 个用户,则将下一个分片(构建已知的 key_name)添加到 fetch 列表中,然后重复。您还可以添加分片计数,以便您可以轻松地预先构建所有 key_names。但你真的要一次吸引 5000 多个用户吗?
    【解决方案2】:

    食物和用户关系是所谓的Many-to-Many relationship,通常使用连接表处理;在这种情况下,db.Model 链接用户和食物。 像这样的:

    class User(db.Model):
      name = db.StringProperty()
    
      def get_food_I_like(self):
         return (entity.name for entity in self.foods)
    
    class Food(db.Model):
      name = db.StringProperty()
    
      def get_users_who_like_me(self):
        return (entity.name for entity in self.users)
    
    class UserFood(db.Model):
      user= db.ReferenceProperty(User, collection_name='foods')
      food = db.ReferenceProperty(Food, collection_name='users')
    

    对于给定用户的实体,您可以通过以下方式检索首选食物:

    userXXX.get_food_I_like()
    

    对于给定的 Food 实体,您可以通过以下方式检索喜欢该食物的用户:

    foodYYY.get_users_who_like_me()
    

    还有另一种处理多对多关系的方法,将键列表存储在 db.ListProperty() 中。

    class Food(db.Model):
      name = db.StringProperty()
    
    class User(db.Model):
      name = db.StringProperty()
      food = db.ListProperty(db.Key)
    

    请记住,ListProperty 限制为 5.000 个键,否则您无法添加完全适合连接表的有用属性(例如:代表用户对食物的喜爱程度的星数)。

    【讨论】:

    • 使用get_food_I_like 函数时要非常小心。它将为每个喜欢食物的用户进行额外的数据存储调用。
    • 感谢 systempuntoout.. 但这又使用了一个数据存储调用。例如:-用户登录后,我将不得不执行类似 food=userxx.get_food_i_like() 的操作,然后再次查找所有喜欢该食物的用户 users=foodYYY.get_users_who_like_me()。目标是当用户登录时,将所有用户显示在一个小屏幕上。我尝试了一些可行的方法,但是我也可能错了,如果有人可以看一下就好了
    • 请您看看我在原帖中制定的解决方案。请指教!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 2017-01-22
    • 2019-02-06
    • 2015-09-20
    • 1970-01-01
    相关资源
    最近更新 更多