Google app engine 如何展平a';友谊';GAE中用户模型中的模型?

Google app engine 如何展平a';友谊';GAE中用户模型中的模型?,google-app-engine,google-cloud-datastore,app-engine-ndb,Google App Engine,Google Cloud Datastore,App Engine Ndb,我最近看到了一些文章,指出要为NoSQL数据库扁平化数据。来自传统的SQL数据库,我意识到我正在GAE中复制一个SQL db bahaviour。所以我开始尽可能地重构代码 例如,我们有一个社交媒体网站,用户可以在其中成为朋友 class Friendship(ndb.Model): from_friend = ndb.KeyProperty(kind=User) to_friend = ndb.KeyProperty(kind=User) 实际上,该应用程序在两个用户之间创建了一

我最近看到了一些文章,指出要为NoSQL数据库扁平化数据。来自传统的SQL数据库,我意识到我正在GAE中复制一个SQL db bahaviour。所以我开始尽可能地重构代码

例如,我们有一个社交媒体网站,用户可以在其中成为朋友

class Friendship(ndb.Model):
   from_friend = ndb.KeyProperty(kind=User)
   to_friend = ndb.KeyProperty(kind=User)
实际上,该应用程序在两个用户之间创建了一个友谊实例

friendshipA = Friendship(from_friend = UserA, to_friend = userB)
friendshipB = Friendship(from_friend = UserB, to_friend = userA)
我现在如何将其移动到实际的用户模型以将其展平。我想也许我可以使用StructuredProperty。我知道它被限制在5000条以内,但这对朋友来说应该足够了

class User(UserMixin, ndb.Model):
     name = ndb.StringProperty()
     friends = ndb.StructuredProperty(User, repeated=True)
所以我想到了这个,但用户不能指向自己,所以看起来。因为我得到一个
name错误:未定义名称“User”


您知道如何将其展平,以便单个用户实例包含其所有好友及其所有属性吗?

使用存储用户实例密钥的KeyProperty。

您不能创建引用自身的StructuredProperty。此外,使用StructuredProperty存储
用户
的副本还存在另一个问题,即如果用户修改了存储的属性,则需要执行手动级联更新

但是,由于KeyProperty接受字符串为
kind
,您可以按照@dragonx的建议轻松存储使用KeyProperty的用户列表。您可以使用
ndb.get_multi
进一步优化读取,以避免在检索朋友时进行多次往返RPC调用

下面是一个示例代码:

class User(ndb.Model):
     name = ndb.StringProperty()
     friends = ndb.KeyProperty(kind="User", repeated=True)

userB = User(name="User B")
userB_key = userB.put()

userC = User(name="User C")
userC_key = userC.put()

userA = User(name="User A", friends=[userB_key, userC_key])
userA_key = userA.put()

# To retrieve all friends
for user in ndb.get_multi(userA.friends):
    print "user: %s" % user.name

但这就像是一种外国风格。我会收集朋友的钥匙,但不是他们的名字等。你知道我的意思吗?它还不是完全平坦的…但(重复的)KeyProperty是您应该做的。让一个用户实例包含其所有好友的副本的想法是行不通的,因为它包含的副本在任何好友更新其属性时都不会更新。您可以使用带有字符串的
ListProperty
作为用户所有好友的ID。它不是很OOP,但很简单。